add row data inspect in admin #10

Merged
kdletters merged 8 commits from hermes/hermes-f32d3246 into master 2026-05-08 20:17:41 +08:00
3 changed files with 100 additions and 13 deletions
Showing only changes of commit b995809f75 - Show all commits

View File

@@ -28,6 +28,7 @@ export function AdminDatabaseTablesPage({
const [result, setResult] = useState<AdminDatabaseTableRowsResponse | null>(null);
const [detailRow, setDetailRow] = useState<AdminDatabaseTableRowPayload | null>(null);
const [errorMessage, setErrorMessage] = useState('');
const [copyMessage, setCopyMessage] = useState('');
const [isLoadingTables, setIsLoadingTables] = useState(false);
const [isLoadingRows, setIsLoadingRows] = useState(false);
@@ -91,20 +92,31 @@ export function AdminDatabaseTablesPage({
}
}
async function refreshRows(nextTableName = tableName) {
async function refreshRows(
nextTableName = tableName,
options: {
search?: string;
filters?: string;
limit?: string;
} = {},
) {
const normalizedTableName = nextTableName.trim();
if (!normalizedTableName) {
return;
}
const querySearch = options.search ?? search;
const queryFilters = options.filters ?? filters;
const queryLimit = options.limit ?? limit;
setIsLoadingRows(true);
setErrorMessage('');
try {
const response = await getAdminDatabaseTableRows(token, normalizedTableName, {
search,
filters,
limit: parseLimit(limit),
search: querySearch,
filters: queryFilters,
limit: parseLimit(queryLimit),
});
setResult(response);
setCopyMessage('');
} catch (error: unknown) {
handlePageError(error, onUnauthorized, setErrorMessage);
} finally {
@@ -125,6 +137,27 @@ export function AdminDatabaseTablesPage({
}
}
function handleResetQuery() {
setSearch('');
setFilters('');
setLimit('100');
void refreshRows(tableName, {search: '', filters: '', limit: '100'});
}
async function handleCopyDetailJson() {
if (!detailRow) {
return;
}
const copiedText = JSON.stringify(detailRow.raw ?? detailRow.cells, null, 2);
try {
await navigator.clipboard.writeText(copiedText);
setCopyMessage('已复制 JSON');
} catch {
setCopyMessage('复制失败,请手动选中后复制');
}
}
return (
<section className="admin-page admin-page-wide">
<div className="admin-page-heading">
@@ -201,6 +234,20 @@ export function AdminDatabaseTablesPage({
<span>{isLoadingRows ? '查询中' : '查询'}</span>
</button>
</div>
<div className="admin-action-row admin-query-action-row">
<button
className="admin-ghost-button admin-query-reset-button"
disabled={isLoadingRows}
type="button"
onClick={handleResetQuery}
>
</button>
<div className="admin-query-summary">
<span>{tableName || '-'}</span>
<span>{visibleColumns.length}</span>
</div>
</div>
</form>
{errorMessage ? (
@@ -265,6 +312,14 @@ export function AdminDatabaseTablesPage({
<section className="admin-detail-panel" role="dialog" aria-modal="true">
<div className="admin-panel-heading">
<h3></h3>
<div className="admin-detail-actions">
<button
className="admin-secondary-button"
type="button"
onClick={() => void handleCopyDetailJson()}
>
<span> JSON</span>
</button>
<button
className="admin-ghost-button"
title="关闭"
@@ -274,8 +329,10 @@ export function AdminDatabaseTablesPage({
<X size={17} aria-hidden="true" />
</button>
</div>
</div>
{copyMessage ? <div className="admin-status admin-status-ok">{copyMessage}</div> : null}
<pre className="admin-code-block">
{JSON.stringify(detailRow.cells, null, 2)}
{JSON.stringify(detailRow.raw ?? detailRow.cells, null, 2)}
</pre>
</section>
</div>

View File

@@ -327,10 +327,34 @@ button:disabled {
.admin-action-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 10px;
}
.admin-query-action-row {
justify-content: space-between;
}
.admin-query-summary,
.admin-detail-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.admin-query-summary {
color: #667682;
font-size: 12px;
font-weight: 650;
}
.admin-query-reset-button {
width: auto;
padding: 0 12px;
}
.admin-field {
display: grid;
min-width: 0;

View File

@@ -11,6 +11,12 @@
- 提供基础查询能力表选择、关键词搜索、JSON 条件过滤、条数限制、刷新、查看行详情。
- 不修改 SpacetimeDB 表结构,不新增 reducer不引入写操作。
## 后续增强
- 查询页增加“重置条件”快捷操作,便于运营快速回到默认筛选状态。
- 行详情支持一键复制完整 JSON减少人工选中复制的操作成本。
- 查询页顶部增加轻量摘要,显示当前选表和可见列数,方便移动端快速确认上下文。
## 后端接口
### `GET /admin/api/database/tables`