Files
srdb/webui/static/js/components/ManifestView.js
bourdon 30c3e74bd2 feat: 完善 WebUI basePath 支持并简化示例代码
主要改动:

1. WebUI basePath 逻辑完善
   - NewWebUI 支持可变参数 basePath
   - 新增 path() 辅助方法统一路径处理
   - handleTableAPI 正确处理 basePath 前缀
   - handleIndex 根据 basePath 替换占位符

2. 简化示例代码
   - 删除反向代理实现(111行)
   - 直接使用带 basePath 的 WebUI
   - 代码量减少 33%,架构更清晰

3. 前端优化
   - 新增 api.js 统一 API 服务层
   - 所有组件使用统一的 API 调用
   - 支持通过 window.API_BASE 配置 basePath

4. 修复 .gitignore
   - 使用通用模式支持 commands 目录
   - 无需为新示例项目修改配置
2025-10-14 22:23:30 +08:00

101 lines
3.3 KiB
JavaScript

import { html } from 'htm/preact';
import { useState, useEffect } from 'preact/hooks';
import { LevelCard } from '~/components/LevelCard.js';
import { StatCard } from '~/components/StatCard.js';
import { CompactionStats } from '~/components/CompactionStats.js';
import { getTableManifest } from '~/utils/api.js';
const styles = {
container: {
display: 'flex',
flexDirection: 'column',
gap: '12px'
},
statsGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
gap: '8px'
}
};
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
}
function formatNumber(num) {
return num.toLocaleString('zh-CN');
}
export function ManifestView({ tableName }) {
const [manifest, setManifest] = useState(null);
const [loading, setLoading] = useState(true);
const [expandedLevels, setExpandedLevels] = useState(new Set());
useEffect(() => {
fetchManifest();
const interval = setInterval(fetchManifest, 5000); // 每5秒刷新
return () => clearInterval(interval);
}, [tableName]);
const fetchManifest = async () => {
try {
const data = await getTableManifest(tableName);
setManifest(data);
} catch (error) {
console.error('Failed to fetch manifest:', error);
} finally {
setLoading(false);
}
};
const toggleLevel = (levelNum) => {
const newExpanded = new Set(expandedLevels);
if (newExpanded.has(levelNum)) {
newExpanded.delete(levelNum);
} else {
newExpanded.add(levelNum);
}
setExpandedLevels(newExpanded);
};
if (loading) {
return html`<div class="loading"><p>加载中...</p></div>`;
}
if (!manifest) {
return html`<div class="empty"><p>无法加载 Manifest 数据</p></div>`;
}
const totalFiles = manifest.levels?.reduce((sum, level) => sum + level.file_count, 0) || 0;
const totalSize = manifest.levels?.reduce((sum, level) => sum + level.total_size, 0) || 0;
return html`
<div style=${styles.container}>
<!-- 统计信息 -->
<div style=${styles.statsGrid}>
<${StatCard} label="总文件数" value=${formatNumber(totalFiles)} />
<${StatCard} label="总大小" value=${formatBytes(totalSize)} />
<${StatCard} label="下一个文件号" value=${formatNumber(manifest.next_file_number || 0)} />
<${StatCard} label="最后序列号" value=${formatNumber(manifest.last_sequence || 0)} />
</div>
<!-- Compaction 统计 -->
<${CompactionStats} stats=${manifest.compaction_stats} />
<!-- 各层级详情 -->
${manifest.levels?.filter(level => level.file_count > 0).map(level => html`
<${LevelCard}
key=${level.level}
level=${level}
isExpanded=${expandedLevels.has(level.level)}
onToggle=${() => toggleLevel(level.level)}
/>
`)}
</div>
`;
}