diff --git a/src/mcp_feedback_enhanced/web/locales/en/translation.json b/src/mcp_feedback_enhanced/web/locales/en/translation.json index b3d4f88..70b4f49 100644 --- a/src/mcp_feedback_enhanced/web/locales/en/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/en/translation.json @@ -236,7 +236,8 @@ "confirmClear": "Are you sure you want to clear all session history?", "exportSuccess": "Session history exported successfully", "clearSuccess": "Session history cleared successfully", - "description": "Manage locally stored session history records, including retention period settings and data export functionality" + "description": "Manage locally stored session history records, including retention period settings and data export functionality", + "exportDescription": "Export or clear locally stored session history records" }, "retention": { "24hours": "24 hours", @@ -244,6 +245,32 @@ "168hours": "7 days", "720hours": "30 days", "custom": "Custom" + }, + "userMessages": { + "title": "User Message Recording", + "description": "Control whether to record user submitted feedback messages in session history", + "recordingEnabled": "Enable Message Recording", + "privacyLevel": "Privacy Level", + "privacyLevels": { + "full": "Full Recording", + "basic": "Basic Statistics", + "disabled": "Disable Recording" + }, + "privacyDescription": { + "full": "Record complete message content and image information", + "basic": "Only record message length, image count and other statistics", + "disabled": "Do not record any user message content" + }, + "messageCount": "Message Count", + "submissionMethod": "Submission Method", + "manual": "Manual Submit", + "auto": "Auto Submit", + "contentLength": "Content Length", + "imageCount": "Image Count", + "timestamp": "Timestamp", + "clearAll": "Clear Message Records", + "confirmClearAll": "Are you sure you want to clear all user message records from all sessions? This action cannot be undone.", + "clearSuccess": "User message records cleared successfully" } }, "connectionMonitor": { diff --git a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json index 0724442..5c7d697 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json @@ -236,7 +236,8 @@ "confirmClear": "确定要清空所有会话历史吗?", "exportSuccess": "会话历史已导出", "clearSuccess": "会话历史已清空", - "description": "管理本地存储的会话历史记录,包括保存期限设定和数据导出功能" + "description": "管理本地存储的会话历史记录,包括保存期限设定和数据导出功能", + "exportDescription": "导出或清空本地存储的会话历史记录" }, "retention": { "24hours": "24 小时", @@ -244,6 +245,32 @@ "168hours": "7 天", "720hours": "30 天", "custom": "自定义" + }, + "userMessages": { + "title": "用户消息记录", + "description": "控制是否记录用户提交的反馈消息到会话历史中", + "recordingEnabled": "启用消息记录", + "privacyLevel": "隐私等级", + "privacyLevels": { + "full": "完整记录", + "basic": "基本统计", + "disabled": "停用记录" + }, + "privacyDescription": { + "full": "记录完整的消息内容和图片信息", + "basic": "仅记录消息长度、图片数量等统计信息", + "disabled": "不记录任何用户消息内容" + }, + "messageCount": "消息数量", + "submissionMethod": "提交方式", + "manual": "手动提交", + "auto": "自动提交", + "contentLength": "内容长度", + "imageCount": "图片数量", + "timestamp": "时间戳", + "clearAll": "清空消息记录", + "confirmClearAll": "确定要清空所有会话的用户消息记录吗?此操作无法撤销。", + "clearSuccess": "用户消息记录已清空" } }, "connectionMonitor": { diff --git a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json index 559800a..90d26f6 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json @@ -241,7 +241,8 @@ "confirmClear": "確定要清空所有會話歷史嗎?", "exportSuccess": "會話歷史已匯出", "clearSuccess": "會話歷史已清空", - "description": "管理本地儲存的會話歷史記錄,包括保存期限設定和資料匯出功能" + "description": "管理本地儲存的會話歷史記錄,包括保存期限設定和資料匯出功能", + "exportDescription": "匯出或清空本地儲存的會話歷史記錄" }, "retention": { "24hours": "24 小時", @@ -249,6 +250,32 @@ "168hours": "7 天", "720hours": "30 天", "custom": "自訂" + }, + "userMessages": { + "title": "用戶訊息記錄", + "description": "控制是否記錄用戶提交的回饋訊息到會話歷史中", + "recordingEnabled": "啟用訊息記錄", + "privacyLevel": "隱私等級", + "privacyLevels": { + "full": "完整記錄", + "basic": "基本統計", + "disabled": "停用記錄" + }, + "privacyDescription": { + "full": "記錄完整的訊息內容和圖片資訊", + "basic": "僅記錄訊息長度、圖片數量等統計資訊", + "disabled": "不記錄任何用戶訊息內容" + }, + "messageCount": "訊息數量", + "submissionMethod": "提交方式", + "manual": "手動提交", + "auto": "自動提交", + "contentLength": "內容長度", + "imageCount": "圖片數量", + "timestamp": "時間戳記", + "clearAll": "清空訊息記錄", + "confirmClearAll": "確定要清空所有會話的用戶訊息記錄嗎?此操作無法復原。", + "clearSuccess": "用戶訊息記錄已清空" } }, "connectionMonitor": { diff --git a/src/mcp_feedback_enhanced/web/static/css/session-management.css b/src/mcp_feedback_enhanced/web/static/css/session-management.css index ee81708..e2e2ea2 100644 --- a/src/mcp_feedback_enhanced/web/static/css/session-management.css +++ b/src/mcp_feedback_enhanced/web/static/css/session-management.css @@ -877,6 +877,148 @@ border-color: var(--accent-color); } +/* ===== 用戶訊息記錄樣式 ===== */ +.user-messages-section { + margin-top: 16px; + border-top: 1px solid var(--border-color); + padding-top: 16px; +} + +.user-messages-summary { + margin-bottom: 12px; + padding: 8px 12px; + background: var(--bg-tertiary); + border-radius: 6px; + font-size: 13px; + color: var(--text-secondary); +} + +.user-messages-list { + max-height: 300px; + overflow-y: auto; + border: 1px solid var(--border-color); + border-radius: 6px; + background: var(--bg-primary); +} + +.user-message-item { + padding: 12px; + border-bottom: 1px solid var(--border-color); + transition: background var(--transition-fast) ease; +} + +.user-message-item:last-child { + border-bottom: none; +} + +.user-message-item:hover { + background: var(--bg-secondary); +} + +.message-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + font-size: 12px; +} + +.message-index { + background: var(--accent-color); + color: white; + padding: 2px 6px; + border-radius: 10px; + font-weight: 500; + font-size: 10px; +} + +.message-time { + color: var(--text-secondary); + font-family: 'Consolas', 'Monaco', monospace; +} + +.message-method { + padding: 2px 8px; + border-radius: 12px; + font-size: 10px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.message-method:contains("自動") { + background: rgba(255, 152, 0, 0.2); + color: var(--warning-color); + border: 1px solid var(--warning-color); +} + +.message-method:contains("手動") { + background: rgba(76, 175, 80, 0.2); + color: var(--success-color); + border: 1px solid var(--success-color); +} + +.message-content, +.message-stats { + font-size: 13px; + line-height: 1.4; + color: var(--text-primary); + background: var(--bg-secondary); + padding: 8px 12px; + border-radius: 4px; + border-left: 3px solid var(--accent-color); +} + +.message-content strong, +.message-stats strong { + color: var(--text-secondary); + font-weight: 500; +} + +.message-images { + margin-top: 8px; + font-size: 12px; + color: var(--text-secondary); +} + +/* 隱私等級選擇器樣式增強 */ +#userMessagePrivacyLevel { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + color: var(--text-primary); + border-radius: 6px; + padding: 6px 12px; + font-size: 13px; + transition: all var(--transition-fast) ease; +} + +#userMessagePrivacyLevel:focus { + outline: none; + border-color: var(--accent-color); + box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.2); +} + +#userMessagePrivacyLevel option { + background: var(--bg-secondary); + color: var(--text-primary); +} + +/* 用戶訊息記錄開關樣式已整合到標準切換開關樣式中 */ + +/* 切換開關容器樣式 */ +.toggle-container { + display: flex; + align-items: center; + gap: 12px; +} + +.toggle-label { + font-size: 13px; + color: var(--text-primary); + cursor: pointer; + user-select: none; +} + /* 減少動畫偏好 */ @media (prefers-reduced-motion: reduce) { * { diff --git a/src/mcp_feedback_enhanced/web/static/js/app.js b/src/mcp_feedback_enhanced/web/static/js/app.js index 1a106ab..851c9fd 100644 --- a/src/mcp_feedback_enhanced/web/static/js/app.js +++ b/src/mcp_feedback_enhanced/web/static/js/app.js @@ -831,6 +831,9 @@ }); if (success) { + // 記錄用戶訊息到會話歷史 + this.recordUserMessage(feedbackData); + // 清空表單 this.clearFeedback(); console.log('📤 回饋已發送,等待服務器確認...'); @@ -850,6 +853,44 @@ } }; + /** + * 記錄用戶訊息到會話歷史 + */ + FeedbackApp.prototype.recordUserMessage = function(feedbackData) { + console.log('📝 記錄用戶訊息到會話歷史...'); + + try { + // 檢查是否有會話管理器 + if (!this.sessionManager || !this.sessionManager.dataManager) { + console.warn('📝 會話管理器未初始化,跳過用戶訊息記錄'); + return; + } + + // 判斷提交方式 + const submissionMethod = this.autoSubmitManager && this.autoSubmitManager.isEnabled ? 'auto' : 'manual'; + + // 建立訊息記錄資料 + const messageData = { + content: feedbackData.feedback || '', + images: feedbackData.images || [], + submission_method: submissionMethod + }; + + // 記錄到會話歷史 + const success = this.sessionManager.dataManager.addUserMessage(messageData); + + if (success) { + console.log('📝 用戶訊息已記錄到會話歷史'); + } else { + console.log('📝 用戶訊息記錄被跳過(可能因隱私設定或其他原因)'); + } + + } catch (error) { + console.error('❌ 記錄用戶訊息失敗:', error); + // 不影響主要功能,只記錄錯誤 + } + }; + /** * 清空回饋內容 */ diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js index ffc6d66..c0d5b32 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-data-manager.js @@ -205,9 +205,19 @@ // 新增儲存時間戳記 sessionData.saved_at = TimeUtils.getCurrentTimestamp(); + // 確保 user_messages 陣列存在(向後相容) + if (!sessionData.user_messages) { + sessionData.user_messages = []; + } + // 避免重複新增 const existingIndex = this.sessionHistory.findIndex(s => s.session_id === sessionData.session_id); if (existingIndex !== -1) { + // 合併用戶訊息記錄 + const existingSession = this.sessionHistory[existingIndex]; + if (existingSession.user_messages && sessionData.user_messages) { + sessionData.user_messages = this.mergeUserMessages(existingSession.user_messages, sessionData.user_messages); + } this.sessionHistory[existingIndex] = sessionData; } else { this.sessionHistory.unshift(sessionData); @@ -231,6 +241,185 @@ return true; }; + /** + * 合併用戶訊息記錄 + */ + SessionDataManager.prototype.mergeUserMessages = function(existingMessages, newMessages) { + const merged = existingMessages.slice(); // 複製現有訊息 + + // 新增不重複的訊息(基於時間戳記去重) + newMessages.forEach(function(newMsg) { + const exists = merged.some(function(existingMsg) { + return existingMsg.timestamp === newMsg.timestamp; + }); + if (!exists) { + merged.push(newMsg); + } + }); + + // 按時間戳記排序 + merged.sort(function(a, b) { + return a.timestamp - b.timestamp; + }); + + return merged; + }; + + /** + * 新增用戶訊息到當前會話 + */ + SessionDataManager.prototype.addUserMessage = function(messageData) { + console.log('📊 新增用戶訊息:', messageData); + + // 檢查隱私設定 + if (!this.isUserMessageRecordingEnabled()) { + console.log('📊 用戶訊息記錄已停用,跳過記錄'); + return false; + } + + // 檢查是否有當前會話 + if (!this.currentSession || !this.currentSession.session_id) { + console.warn('📊 沒有當前會話,無法記錄用戶訊息'); + return false; + } + + // 確保當前會話有 user_messages 陣列 + if (!this.currentSession.user_messages) { + this.currentSession.user_messages = []; + } + + // 建立用戶訊息記錄 + const userMessage = this.createUserMessageRecord(messageData); + + // 新增到當前會話 + this.currentSession.user_messages.push(userMessage); + + console.log('📊 用戶訊息已記錄到當前會話:', this.currentSession.session_id); + return true; + }; + + /** + * 建立用戶訊息記錄 + */ + SessionDataManager.prototype.createUserMessageRecord = function(messageData) { + const timestamp = TimeUtils.getCurrentTimestamp(); + const privacyLevel = this.getUserMessagePrivacyLevel(); + + const record = { + timestamp: timestamp, + submission_method: messageData.submission_method || 'manual', + type: 'feedback' + }; + + // 根據隱私等級決定記錄內容 + if (privacyLevel === 'full') { + record.content = messageData.content || ''; + record.images = this.processImageDataForRecord(messageData.images || []); + } else if (privacyLevel === 'basic') { + record.content_length = (messageData.content || '').length; + record.image_count = (messageData.images || []).length; + record.has_content = !!(messageData.content && messageData.content.trim()); + } else if (privacyLevel === 'disabled') { + // 停用記錄時,只記錄最基本的時間戳記和提交方式 + record.privacy_note = 'Content recording disabled by user privacy settings'; + } + + return record; + }; + + /** + * 處理圖片資料用於記錄 + */ + SessionDataManager.prototype.processImageDataForRecord = function(images) { + if (!Array.isArray(images)) { + return []; + } + + return images.map(function(img) { + return { + name: img.name || 'unknown', + size: img.size || 0, + type: img.type || 'unknown' + }; + }); + }; + + /** + * 檢查是否啟用用戶訊息記錄 + */ + SessionDataManager.prototype.isUserMessageRecordingEnabled = function() { + if (!this.settingsManager) { + return true; // 預設啟用 + } + + // 檢查總開關 + const recordingEnabled = this.settingsManager.get('userMessageRecordingEnabled', true); + if (!recordingEnabled) { + return false; + } + + // 檢查隱私等級(disabled 等級視為停用記錄) + const privacyLevel = this.settingsManager.get('userMessagePrivacyLevel', 'full'); + return privacyLevel !== 'disabled'; + }; + + /** + * 獲取用戶訊息隱私等級 + */ + SessionDataManager.prototype.getUserMessagePrivacyLevel = function() { + if (!this.settingsManager) { + return 'full'; // 預設完整記錄 + } + return this.settingsManager.get('userMessagePrivacyLevel', 'full'); + }; + + /** + * 清空所有會話的用戶訊息記錄 + */ + SessionDataManager.prototype.clearAllUserMessages = function() { + console.log('📊 清空所有會話的用戶訊息記錄...'); + + // 清空當前會話的用戶訊息 + if (this.currentSession && this.currentSession.user_messages) { + this.currentSession.user_messages = []; + } + + // 清空歷史會話的用戶訊息 + this.sessionHistory.forEach(function(session) { + if (session.user_messages) { + session.user_messages = []; + } + }); + + // 保存到 localStorage + this.saveToLocalStorage(); + + console.log('📊 所有用戶訊息記錄已清空'); + return true; + }; + + /** + * 清空指定會話的用戶訊息記錄 + */ + SessionDataManager.prototype.clearSessionUserMessages = function(sessionId) { + console.log('📊 清空會話用戶訊息記錄:', sessionId); + + // 查找並清空指定會話的用戶訊息 + const session = this.sessionHistory.find(function(s) { + return s.session_id === sessionId; + }); + + if (session && session.user_messages) { + session.user_messages = []; + this.saveToLocalStorage(); + console.log('📊 會話用戶訊息記錄已清空:', sessionId); + return true; + } + + console.warn('📊 找不到指定會話或該會話沒有用戶訊息記錄:', sessionId); + return false; + }; + /** * 獲取當前會話 */ @@ -479,11 +668,12 @@ * 匯出會話歷史 */ SessionDataManager.prototype.exportSessionHistory = function() { + const self = this; const exportData = { exportedAt: new Date().toISOString(), totalSessions: this.sessionHistory.length, sessions: this.sessionHistory.map(function(session) { - return { + const sessionData = { session_id: session.session_id, created_at: session.created_at, completed_at: session.completed_at, @@ -493,6 +683,14 @@ ai_summary: session.summary || session.ai_summary, saved_at: session.saved_at }; + + // 包含用戶訊息記錄(如果存在且允許匯出) + if (session.user_messages && self.isUserMessageRecordingEnabled()) { + sessionData.user_messages = session.user_messages; + sessionData.user_message_count = session.user_messages.length; + } + + return sessionData; }) }; @@ -516,18 +714,26 @@ return null; } + const sessionData = { + session_id: session.session_id, + created_at: session.created_at, + completed_at: session.completed_at, + duration: session.duration, + status: session.status, + project_directory: session.project_directory, + ai_summary: session.summary || session.ai_summary, + saved_at: session.saved_at + }; + + // 包含用戶訊息記錄(如果存在且允許匯出) + if (session.user_messages && this.isUserMessageRecordingEnabled()) { + sessionData.user_messages = session.user_messages; + sessionData.user_message_count = session.user_messages.length; + } + const exportData = { exportedAt: new Date().toISOString(), - session: { - session_id: session.session_id, - created_at: session.created_at, - completed_at: session.completed_at, - duration: session.duration, - status: session.status, - project_directory: session.project_directory, - ai_summary: session.summary || session.ai_summary, - saved_at: session.saved_at - } + session: sessionData }; const shortId = sessionId.substring(0, 8); diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js index 746a02a..de55fb9 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js @@ -88,6 +88,10 @@ const statusText = StatusUtils.getStatusText(status); const statusColor = StatusUtils.getStatusColor(status); + // 處理用戶訊息記錄 + const userMessages = sessionData.user_messages || []; + const userMessageCount = userMessages.length; + return { sessionId: sessionId, status: statusText, @@ -95,7 +99,9 @@ createdTime: createdTime, duration: duration, projectDirectory: sessionData.project_directory || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知'), - summary: sessionData.summary || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.noSummary') : '暫無摘要') + summary: sessionData.summary || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.noSummary') : '暫無摘要'), + userMessages: userMessages, + userMessageCount: userMessageCount }; }; @@ -162,6 +168,7 @@ ${i18n ? i18n.t('sessionManagement.aiSummary') : 'AI 摘要'}:
${this.escapeHtml(details.summary)}
+ ${this.createUserMessagesSection(details)} +
+
+
用戶訊息記錄
+
+ 控制是否記錄用戶提交的回饋訊息到會話歷史中 +
+
+
+
+ + 啟用訊息記錄 +
+
+
+ +
+
+
隱私等級
+
+ 記錄完整的訊息內容和圖片資訊 +
+
+
+ +
+
+
資料管理
-
+
匯出或清空本地儲存的會話歷史記錄
-
+
+