Optimize the insight view component, add internationalization support, update log output, improve user interaction prompts, and ensure better user experience and code readability.

This commit is contained in:
duanfuxiang 2025-07-06 07:20:07 +08:00
parent a9c2c7bc16
commit 932b2d3d7f
3 changed files with 186 additions and 52 deletions

View File

@ -67,9 +67,9 @@ const InsightView = () => {
// 设置范围信息 // 设置范围信息
let scopeDescription = '' let scopeDescription = ''
if (currentWorkspace) { if (currentWorkspace) {
scopeDescription = `工作区: ${currentWorkspace.name}` scopeDescription = `${t('insights.fileGroup.workspacePrefix')} ${currentWorkspace.name}`
} else { } else {
scopeDescription = '整个 Vault' scopeDescription = t('insights.stats.scopeLabel') + ' ' + t('workspace.entireVault')
} }
setCurrentScope(scopeDescription) setCurrentScope(scopeDescription)
@ -192,7 +192,7 @@ const InsightView = () => {
// 设置初始进度状态 // 设置初始进度状态
setInitProgress({ setInitProgress({
stage: '准备初始化工作区洞察', stage: t('insights.stage.preparing'),
current: 0, current: 0,
total: 1, total: 1,
currentItem: currentWorkspace.name currentItem: currentWorkspace.name
@ -217,10 +217,10 @@ const InsightView = () => {
// 更新进度为完成状态 // 更新进度为完成状态
setInitProgress({ setInitProgress({
stage: '正在完成初始化', stage: t('insights.stage.completing'),
current: 1, current: 1,
total: 1, total: 1,
currentItem: '保存结果' currentItem: t('insights.stage.savingResults')
}) })
if (result.success) { if (result.success) {
@ -228,15 +228,15 @@ const InsightView = () => {
await loadInsights() await loadInsights()
// 显示成功消息 // 显示成功消息
console.log(`工作区 "${currentWorkspace.name}" 洞察初始化成功`) console.log(t('insights.success.workspaceInitialized', { name: currentWorkspace.name }))
} else { } else {
console.error('工作区洞察初始化失败:', result.error) console.error(t('insights.error.initializationFailed'), result.error)
throw new Error(result.error || '初始化失败') throw new Error(result.error || t('insights.error.initializationFailed'))
} }
} catch (error) { } catch (error) {
console.error('初始化工作区洞察时出错:', error) console.error(t('insights.error.initializationFailed'), error)
// 可以在这里添加错误提示 setInsightResults([])
} finally { } finally {
setIsInitializing(false) setIsInitializing(false)
setInitProgress(null) setInitProgress(null)
@ -266,19 +266,19 @@ const InsightView = () => {
if (result.success) { if (result.success) {
const workspaceName = currentWorkspace?.name || 'vault' const workspaceName = currentWorkspace?.name || 'vault'
console.log(`工作区 "${workspaceName}" 的 ${result.deletedCount} 个转换已成功删除`) console.log(t('insights.success.workspaceDeleted', { name: workspaceName, count: result.deletedCount }))
// 刷新洞察列表 // 刷新洞察列表
await loadInsights() await loadInsights()
// 可以在这里添加用户通知,比如显示删除成功的消息 // 可以在这里添加用户通知,比如显示删除成功的消息
} else { } else {
console.error('删除工作区洞察失败:', result.error) console.error(t('insights.error.deletionFailed'), result.error)
// 可以在这里添加错误提示 // 可以在这里添加错误提示
} }
} catch (error) { } catch (error) {
console.error('删除工作区洞察时出错:', error) console.error(t('insights.error.deletionFailed'), error)
// 可以在这里添加错误提示 // 可以在这里添加错误提示
} finally { } finally {
setIsDeleting(false) setIsDeleting(false)
@ -307,17 +307,17 @@ const InsightView = () => {
const result = await transEngine.deleteSingleInsight(insightId) const result = await transEngine.deleteSingleInsight(insightId)
if (result.success) { if (result.success) {
console.log(`洞察 ID ${insightId} 已成功删除`) console.log(t('insights.success.insightDeleted', { id: insightId }))
// 刷新洞察列表 // 刷新洞察列表
await loadInsights() await loadInsights()
} else { } else {
console.error('删除洞察失败:', result.error) console.error(t('insights.error.singleDeletionFailed'), result.error)
// 可以在这里添加错误提示 // 可以在这里添加错误提示
} }
} catch (error) { } catch (error) {
console.error('删除洞察时出错:', error) console.error(t('insights.error.singleDeletionFailed'), error)
// 可以在这里添加错误提示 // 可以在这里添加错误提示
} finally { } finally {
setDeletingInsightId(null) setDeletingInsightId(null)
@ -341,7 +341,7 @@ const InsightView = () => {
// 检查路径是否存在 // 检查路径是否存在
if (!insight.source_path) { if (!insight.source_path) {
console.error('❌ [InsightView] 文件路径为空') console.error(t('insights.error.fileNotFound') + ' ' + insight.source_path)
return return
} }
@ -367,14 +367,14 @@ const InsightView = () => {
} }
console.debug('✅ [InsightView] 在文件管理器中显示文件夹') console.debug('✅ [InsightView] 在文件管理器中显示文件夹')
} else { } else {
console.warn('❌ [InsightView] 文件夹不存在:', insight.source_path) console.warn(t('insights.error.folderNotFound'), insight.source_path)
} }
return return
} else { } else {
// 文件洞察 - 正常打开文件 // 文件洞察 - 正常打开文件
const file = app.vault.getFileByPath(insight.source_path) const file = app.vault.getFileByPath(insight.source_path)
if (!file) { if (!file) {
console.error('❌ [InsightView] 在vault中找不到文件:', insight.source_path) console.error(t('insights.error.fileNotFound'), insight.source_path)
return return
} }
@ -422,10 +422,10 @@ const InsightView = () => {
// 根据源路径类型确定显示名称和类型 // 根据源路径类型确定显示名称和类型
if (sourcePath.startsWith('workspace:')) { if (sourcePath.startsWith('workspace:')) {
const workspaceName = sourcePath.replace('workspace:', '') const workspaceName = sourcePath.replace('workspace:', '')
displayName = `🌐 工作区: ${workspaceName}` displayName = `${t('insights.fileGroup.workspacePrefix')} ${workspaceName}`
groupType = 'workspace' groupType = 'workspace'
} else if (result.source_type === 'folder') { } else if (result.source_type === 'folder') {
displayName = `📁 ${sourcePath.split('/').pop() || sourcePath}` displayName = `${t('insights.fileGroup.folderPrefix')} ${sourcePath.split('/').pop() || sourcePath}`
groupType = 'folder' groupType = 'folder'
} else { } else {
displayName = sourcePath.split('/').pop() || sourcePath displayName = sourcePath.split('/').pop() || sourcePath
@ -472,12 +472,12 @@ const InsightView = () => {
// 获取洞察类型的显示名称 // 获取洞察类型的显示名称
const getInsightTypeDisplayName = (insightType: string) => { const getInsightTypeDisplayName = (insightType: string) => {
const typeMapping: Record<string, string> = { const typeMapping: Record<string, string> = {
'dense_summary': '📋 密集摘要', 'dense_summary': t('insights.types.denseSummary'),
'simple_summary': '📄 简单摘要', 'simple_summary': t('insights.types.simpleSummary'),
'key_insights': '💡 关键洞察', 'key_insights': t('insights.types.keyInsights'),
'analyze_paper': '🔬 论文分析', 'analyze_paper': t('insights.types.analyzePaper'),
'table_of_contents': '📑 目录大纲', 'table_of_contents': t('insights.types.tableOfContents'),
'reflections': '🤔 思考反思' 'reflections': t('insights.types.reflections')
} }
return typeMapping[insightType] || insightType.toUpperCase() return typeMapping[insightType] || insightType.toUpperCase()
} }
@ -487,30 +487,30 @@ const InsightView = () => {
{/* 头部信息 */} {/* 头部信息 */}
<div className="obsidian-insight-header"> <div className="obsidian-insight-header">
<div className="obsidian-insight-title"> <div className="obsidian-insight-title">
<h3>{t('insights.title') || 'AI 洞察'}</h3> <h3>{t('insights.title')}</h3>
<div className="obsidian-insight-actions"> <div className="obsidian-insight-actions">
<button <button
onClick={initializeWorkspaceInsights} onClick={initializeWorkspaceInsights}
disabled={isInitializing || isLoading || isDeleting} disabled={isInitializing || isLoading || isDeleting}
className="obsidian-insight-init-btn" className="obsidian-insight-init-btn"
title="初始化当前工作区的洞察,会递归处理所有文件并生成摘要" title={t('insights.tooltips.initialize')}
> >
{isInitializing ? '初始化中...' : '初始化洞察'} {isInitializing ? t('insights.initializing') : t('insights.initializeInsights')}
</button> </button>
<button <button
onClick={handleDeleteWorkspaceInsights} onClick={handleDeleteWorkspaceInsights}
disabled={isDeleting || isLoading || isInitializing} disabled={isDeleting || isLoading || isInitializing}
className="obsidian-insight-delete-btn" className="obsidian-insight-delete-btn"
title="删除当前工作区的所有转换和洞察" title={t('insights.tooltips.clear')}
> >
{isDeleting ? '删除中...' : '清除洞察'} {isDeleting ? t('insights.deleting') : t('insights.clearInsights')}
</button> </button>
<button <button
onClick={loadInsights} onClick={loadInsights}
disabled={isLoading || isInitializing || isDeleting} disabled={isLoading || isInitializing || isDeleting}
className="obsidian-insight-refresh-btn" className="obsidian-insight-refresh-btn"
> >
{isLoading ? '加载中...' : '刷新'} {isLoading ? t('insights.loading') : t('insights.refresh')}
</button> </button>
</div> </div>
</div> </div>
@ -519,23 +519,23 @@ const InsightView = () => {
{hasLoaded && !isLoading && ( {hasLoaded && !isLoading && (
<div className="obsidian-insight-stats"> <div className="obsidian-insight-stats">
<div className="obsidian-insight-stats-line"> <div className="obsidian-insight-stats-line">
{insightGroupedResults.length} {insightResults.length} {t('insights.stats.itemsAndInsights', { items: insightGroupedResults.length, insights: insightResults.length })}
{insightGroupedResults.length > 0 && ( {insightGroupedResults.length > 0 && (
<span className="obsidian-insight-breakdown"> <span className="obsidian-insight-breakdown">
{' '}( {' '}(
{insightGroupedResults.filter(g => g.groupType === 'workspace').length > 0 && {insightGroupedResults.filter(g => g.groupType === 'workspace').length > 0 &&
`${insightGroupedResults.filter(g => g.groupType === 'workspace').length}工作区 `} `${t('insights.stats.workspace', { count: insightGroupedResults.filter(g => g.groupType === 'workspace').length })} `}
{insightGroupedResults.filter(g => g.groupType === 'folder').length > 0 && {insightGroupedResults.filter(g => g.groupType === 'folder').length > 0 &&
`${insightGroupedResults.filter(g => g.groupType === 'folder').length}文件夹 `} `${t('insights.stats.folder', { count: insightGroupedResults.filter(g => g.groupType === 'folder').length })} `}
{insightGroupedResults.filter(g => g.groupType === 'file').length > 0 && {insightGroupedResults.filter(g => g.groupType === 'file').length > 0 &&
`${insightGroupedResults.filter(g => g.groupType === 'file').length}文件`} `${t('insights.stats.file', { count: insightGroupedResults.filter(g => g.groupType === 'file').length })}`}
) )
</span> </span>
)} )}
</div> </div>
{currentScope && ( {currentScope && (
<div className="obsidian-insight-scope"> <div className="obsidian-insight-scope">
: {currentScope} {t('insights.stats.scopeLabel')} {currentScope}
</div> </div>
)} )}
</div> </div>
@ -545,7 +545,7 @@ const InsightView = () => {
{/* 加载进度 */} {/* 加载进度 */}
{isLoading && ( {isLoading && (
<div className="obsidian-insight-loading"> <div className="obsidian-insight-loading">
... {t('insights.loading')}
</div> </div>
)} )}
@ -553,8 +553,8 @@ const InsightView = () => {
{isInitializing && ( {isInitializing && (
<div className="obsidian-insight-initializing"> <div className="obsidian-insight-initializing">
<div className="obsidian-insight-init-header"> <div className="obsidian-insight-init-header">
<h4>...</h4> <h4>{t('insights.initializingWorkspace')}</h4>
<p></p> <p>{t('insights.initializingDescription')}</p>
</div> </div>
{initProgress && ( {initProgress && (
<div className="obsidian-insight-progress"> <div className="obsidian-insight-progress">
@ -573,7 +573,7 @@ const InsightView = () => {
></div> ></div>
</div> </div>
<div className="obsidian-insight-progress-item"> <div className="obsidian-insight-progress-item">
: {initProgress.currentItem} {t('insights.progress.current', { item: initProgress.currentItem })}
</div> </div>
</div> </div>
)} )}
@ -585,17 +585,17 @@ const InsightView = () => {
<div className="obsidian-confirm-dialog-overlay"> <div className="obsidian-confirm-dialog-overlay">
<div className="obsidian-confirm-dialog"> <div className="obsidian-confirm-dialog">
<div className="obsidian-confirm-dialog-header"> <div className="obsidian-confirm-dialog-header">
<h3></h3> <h3>{t('insights.deleteConfirm.title')}</h3>
</div> </div>
<div className="obsidian-confirm-dialog-body"> <div className="obsidian-confirm-dialog-body">
<p> <p>
{t('insights.deleteConfirm.message')}
</p> </p>
<p className="obsidian-confirm-dialog-warning"> <p className="obsidian-confirm-dialog-warning">
{t('insights.deleteConfirm.warning')}
</p> </p>
<div className="obsidian-confirm-dialog-scope"> <div className="obsidian-confirm-dialog-scope">
<strong>:</strong> {currentScope} <strong>{t('insights.deleteConfirm.scopeLabel')}</strong> {currentScope}
</div> </div>
</div> </div>
<div className="obsidian-confirm-dialog-footer"> <div className="obsidian-confirm-dialog-footer">
@ -603,13 +603,13 @@ const InsightView = () => {
onClick={cancelDeleteConfirm} onClick={cancelDeleteConfirm}
className="obsidian-confirm-dialog-cancel-btn" className="obsidian-confirm-dialog-cancel-btn"
> >
{t('insights.deleteConfirm.cancel')}
</button> </button>
<button <button
onClick={confirmDeleteWorkspaceInsights} onClick={confirmDeleteWorkspaceInsights}
className="obsidian-confirm-dialog-confirm-btn" className="obsidian-confirm-dialog-confirm-btn"
> >
{t('insights.deleteConfirm.confirm')}
</button> </button>
</div> </div>
</div> </div>
@ -685,9 +685,9 @@ const InsightView = () => {
deleteSingleInsight(insight.id) deleteSingleInsight(insight.id)
}} }}
disabled={deletingInsightId === insight.id} disabled={deletingInsightId === insight.id}
title="删除此洞察" title={t('insights.tooltips.clear')}
> >
{deletingInsightId === insight.id ? '删除中...' : '🗑️'} {deletingInsightId === insight.id ? t('insights.deleting') : '🗑️'}
</button> </button>
</div> </div>
</div> </div>
@ -707,9 +707,9 @@ const InsightView = () => {
{!isLoading && hasLoaded && insightGroupedResults.length === 0 && ( {!isLoading && hasLoaded && insightGroupedResults.length === 0 && (
<div className="obsidian-no-results"> <div className="obsidian-no-results">
<p></p> <p>{t('insights.noResults.title')}</p>
<p className="obsidian-no-results-hint"> <p className="obsidian-no-results-hint">
AI {t('insights.noResults.hint')}
</p> </p>
</div> </div>
)} )}

View File

@ -494,10 +494,77 @@ export default {
toolNoDescription: "No description", toolNoDescription: "No description",
useMcpToolFrom: "Use MCP tool from", useMcpToolFrom: "Use MCP tool from",
}, },
insights: {
title: "AI Insights",
initializeInsights: "Initialize Insights",
clearInsights: "Clear Insights",
refresh: "Refresh",
initializing: "Initializing...",
deleting: "Deleting...",
loading: "Loading...",
initializingWorkspace: "Initializing workspace insights...",
initializingDescription: "This may take a few minutes, please be patient",
stage: {
preparing: "Preparing to initialize workspace insights",
completing: "Completing initialization",
savingResults: "Saving results"
},
deleteConfirm: {
title: "Confirm Delete",
message: "Are you sure you want to delete all insights for the current workspace?",
warning: "⚠️ This action cannot be undone and will delete all generated transformation and insight data.",
scopeLabel: "Affected scope:",
cancel: "Cancel",
confirm: "Confirm Delete"
},
stats: {
itemsAndInsights: "{items} items, {insights} insights",
workspace: "{count} workspace",
folder: "{count} folder",
file: "{count} file",
scopeLabel: "Scope:"
},
types: {
denseSummary: "📋 Dense Summary",
simpleSummary: "📄 Simple Summary",
keyInsights: "💡 Key Insights",
analyzePaper: "🔬 Paper Analysis",
tableOfContents: "📑 Table of Contents",
reflections: "🤔 Reflections"
},
fileGroup: {
workspacePrefix: "🌐 Workspace:",
folderPrefix: "📁"
},
noResults: {
title: "No insight data found in the current scope",
hint: "Please try running transformation tools on documents to generate AI insights"
},
tooltips: {
initialize: "Initialize insights for the current workspace, will recursively process all files and generate summaries",
clear: "Delete all transformations and insights for the current workspace"
},
success: {
workspaceInitialized: 'Workspace "{name}" insights initialization successful',
workspaceDeleted: 'Successfully deleted {count} transformations for workspace "{name}"',
insightDeleted: 'Insight ID {id} successfully deleted'
},
error: {
initializationFailed: "Workspace insight initialization failed:",
deletionFailed: "Failed to delete workspace insights:",
singleDeletionFailed: "Failed to delete insight:",
fileNotFound: "File not found in vault:",
folderNotFound: "Folder does not exist:"
},
progress: {
current: "Processing: {item}"
}
},
workspace: { workspace: {
title: "Workspace Management", title: "Workspace Management",
shortTitle: "Workspace", shortTitle: "Workspace",
description: "Manage and switch between different workspaces (note vaults)", description: "Manage and switch between different workspaces (note vaults)",
entireVault: "Entire Vault",
createNew: "Create New Workspace", createNew: "Create New Workspace",
recentWorkspaces: "Recent Workspaces", recentWorkspaces: "Recent Workspaces",
loading: "Loading workspace list...", loading: "Loading workspace list...",

View File

@ -496,10 +496,77 @@ export default {
useMcpToolFrom: "使用来自以下的 MCP 工具:", useMcpToolFrom: "使用来自以下的 MCP 工具:",
} }
}, },
insights: {
title: "AI 洞察",
initializeInsights: "初始化洞察",
clearInsights: "清除洞察",
refresh: "刷新",
initializing: "初始化中...",
deleting: "删除中...",
loading: "加载中...",
initializingWorkspace: "正在初始化工作区洞察...",
initializingDescription: "这可能需要几分钟时间,请耐心等待",
stage: {
preparing: "准备初始化工作区洞察",
completing: "正在完成初始化",
savingResults: "保存结果"
},
deleteConfirm: {
title: "确认删除",
message: "您确定要删除当前工作区的所有洞察吗?",
warning: "⚠️ 这个操作不可撤销,将删除所有生成的转换和洞察数据。",
scopeLabel: "影响范围:",
cancel: "取消",
confirm: "确认删除"
},
stats: {
itemsAndInsights: "{items} 个项目,{insights} 个洞察",
workspace: "{count}工作区",
folder: "{count}文件夹",
file: "{count}文件",
scopeLabel: "范围:"
},
types: {
denseSummary: "📋 密集摘要",
simpleSummary: "📄 简单摘要",
keyInsights: "💡 关键洞察",
analyzePaper: "🔬 论文分析",
tableOfContents: "📑 目录大纲",
reflections: "🤔 思考反思"
},
fileGroup: {
workspacePrefix: "🌐 工作区:",
folderPrefix: "📁"
},
noResults: {
title: "当前范围内没有找到洞察数据",
hint: "请尝试在文档上运行转换工具来生成 AI 洞察"
},
tooltips: {
initialize: "初始化当前工作区的洞察,会递归处理所有文件并生成摘要",
clear: "删除当前工作区的所有转换和洞察"
},
success: {
workspaceInitialized: '工作区 "{name}" 洞察初始化成功',
workspaceDeleted: '工作区 "{name}" 的 {count} 个转换已成功删除',
insightDeleted: '洞察 ID {id} 已成功删除'
},
error: {
initializationFailed: "工作区洞察初始化失败:",
deletionFailed: "删除工作区洞察失败:",
singleDeletionFailed: "删除洞察失败:",
fileNotFound: "在vault中找不到文件:",
folderNotFound: "文件夹不存在:"
},
progress: {
current: "正在处理: {item}"
}
},
workspace: { workspace: {
title: "工作区管理", title: "工作区管理",
shortTitle: "工作区", shortTitle: "工作区",
description: "管理和切换不同的工作区(笔记库)", description: "管理和切换不同的工作区(笔记库)",
entireVault: "整个 Vault",
createNew: "创建新工作区", createNew: "创建新工作区",
recentWorkspaces: "最近的工作区", recentWorkspaces: "最近的工作区",
loading: "正在加载工作区列表...", loading: "正在加载工作区列表...",