mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-13 02:41:50 +08:00
Remove backup HTML template for workflow dashboard
This commit is contained in:
134
ccw/src/templates/dashboard-js/utils.js
Normal file
134
ccw/src/templates/dashboard-js/utils.js
Normal file
@@ -0,0 +1,134 @@
|
||||
// ========================================
|
||||
// Utility Functions
|
||||
// ========================================
|
||||
// General-purpose helper functions used across the application
|
||||
|
||||
// ========== HTML/Text Processing ==========
|
||||
|
||||
/**
|
||||
* Escape HTML special characters to prevent XSS attacks
|
||||
* @param {string} str - String to escape
|
||||
* @returns {string} Escaped string safe for HTML insertion
|
||||
*/
|
||||
function escapeHtml(str) {
|
||||
if (typeof str !== 'string') return str;
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate text to specified maximum length
|
||||
* @param {string} text - Text to truncate
|
||||
* @param {number} maxLen - Maximum length (including ellipsis)
|
||||
* @returns {string} Truncated text with '...' if needed
|
||||
*/
|
||||
function truncateText(text, maxLen) {
|
||||
if (!text) return '';
|
||||
return text.length > maxLen ? text.substring(0, maxLen - 3) + '...' : text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize line endings in content
|
||||
* Handles both literal \r\n escape sequences and actual newlines
|
||||
* @param {string} content - Content to normalize
|
||||
* @returns {string} Content with normalized line endings (LF only)
|
||||
*/
|
||||
function normalizeLineEndings(content) {
|
||||
if (!content) return '';
|
||||
let normalized = content;
|
||||
// If content has literal \r\n or \n as text (escaped), convert to actual newlines
|
||||
if (normalized.includes('\\r\\n')) {
|
||||
normalized = normalized.replace(/\\r\\n/g, '\n');
|
||||
} else if (normalized.includes('\\n')) {
|
||||
normalized = normalized.replace(/\\n/g, '\n');
|
||||
}
|
||||
// Normalize CRLF to LF for consistent rendering
|
||||
normalized = normalized.replace(/\r\n/g, '\n');
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// ========== Date/Time Formatting ==========
|
||||
|
||||
/**
|
||||
* Format ISO date string to human-readable format
|
||||
* @param {string} dateStr - ISO date string
|
||||
* @returns {string} Formatted date string (YYYY/MM/DD HH:mm) or '-' if invalid
|
||||
*/
|
||||
function formatDate(dateStr) {
|
||||
if (!dateStr) return '-';
|
||||
try {
|
||||
const date = new Date(dateStr);
|
||||
// Check if date is valid
|
||||
if (isNaN(date.getTime())) return '-';
|
||||
// Format: YYYY/MM/DD HH:mm
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}/${month}/${day} ${hours}:${minutes}`;
|
||||
} catch (e) {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
// ========== UI Helpers ==========
|
||||
|
||||
/**
|
||||
* Get color for relevance score visualization
|
||||
* @param {number} score - Relevance score (0-1)
|
||||
* @returns {string} CSS color value
|
||||
*/
|
||||
function getRelevanceColor(score) {
|
||||
if (score >= 0.95) return '#10b981';
|
||||
if (score >= 0.90) return '#3b82f6';
|
||||
if (score >= 0.80) return '#f59e0b';
|
||||
return '#6b7280';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CSS class for role badge styling
|
||||
* @param {string} role - Role identifier
|
||||
* @returns {string} CSS class name
|
||||
*/
|
||||
function getRoleBadgeClass(role) {
|
||||
const roleMap = {
|
||||
'core-hook': 'primary',
|
||||
'api-client': 'success',
|
||||
'api-router': 'info',
|
||||
'service-layer': 'warning',
|
||||
'pydantic-schemas': 'secondary',
|
||||
'orm-model': 'secondary',
|
||||
'typescript-types': 'info'
|
||||
};
|
||||
return roleMap[role] || 'secondary';
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle collapsible section visibility
|
||||
* @param {HTMLElement} header - Section header element
|
||||
*/
|
||||
function toggleSection(header) {
|
||||
const content = header.nextElementSibling;
|
||||
const icon = header.querySelector('.collapse-icon');
|
||||
const isCollapsed = content.classList.contains('collapsed');
|
||||
|
||||
content.classList.toggle('collapsed');
|
||||
header.classList.toggle('expanded');
|
||||
icon.textContent = isCollapsed ? '▼' : '▶';
|
||||
|
||||
// Render flowchart if expanding flow_control section
|
||||
if (isCollapsed && header.querySelector('.section-label')?.textContent === 'flow_control') {
|
||||
const taskId = content.closest('[data-task-id]')?.dataset.taskId;
|
||||
if (taskId) {
|
||||
const task = taskJsonStore[taskId];
|
||||
if (task?.flow_control) {
|
||||
setTimeout(() => renderFullFlowchart(task.flow_control), 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user