feat: remove OpenSearch, add ClickHouse admin page
Remove all OpenSearch code, dependencies, configuration, deployment manifests, and CI/CD references. Replace the OpenSearch admin page with a ClickHouse admin page showing cluster status, table sizes, performance metrics, and indexer pipeline stats. - Delete 11 OpenSearch Java files (config, search impl, admin controller, DTOs, tests) - Delete 3 OpenSearch frontend files (admin page, CSS, query hooks) - Delete deploy/opensearch.yaml K8s manifest - Remove opensearch Maven dependencies from pom.xml - Remove opensearch config from application.yml, Dockerfile, docker-compose - Remove opensearch from CI workflow (secrets, deploy, cleanup steps) - Simplify ThresholdConfig (remove OpenSearch thresholds, database-only) - Change default search backend from opensearch to clickhouse - Add ClickHouseAdminController with /status, /tables, /performance, /pipeline - Add ClickHouseAdminPage with StatCards, pipeline ProgressBar, tables DataTable - Update CLAUDE.md, HOWTO.md, and source comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
65
ui/src/pages/Admin/ClickHouseAdminPage.tsx
Normal file
65
ui/src/pages/Admin/ClickHouseAdminPage.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { StatCard, DataTable, ProgressBar } from '@cameleer/design-system';
|
||||
import type { Column } from '@cameleer/design-system';
|
||||
import { useClickHouseStatus, useClickHouseTables, useClickHousePerformance, useIndexerPipeline } from '../../api/queries/admin/clickhouse';
|
||||
import styles from './ClickHouseAdminPage.module.css';
|
||||
|
||||
export default function ClickHouseAdminPage() {
|
||||
const { data: status, isError: statusError } = useClickHouseStatus();
|
||||
const { data: tables } = useClickHouseTables();
|
||||
const { data: perf } = useClickHousePerformance();
|
||||
const { data: pipeline } = useIndexerPipeline();
|
||||
const unreachable = statusError || (status && !status.reachable);
|
||||
|
||||
const tableColumns: Column<any>[] = [
|
||||
{ key: 'name', header: 'Table', sortable: true },
|
||||
{ key: 'engine', header: 'Engine' },
|
||||
{ key: 'rowCount', header: 'Rows', sortable: true, render: (v) => Number(v).toLocaleString() },
|
||||
{ key: 'dataSize', header: 'Size', sortable: true },
|
||||
{ key: 'partitionCount', header: 'Partitions', sortable: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.statStrip}>
|
||||
<StatCard label="Status" value={unreachable ? 'Disconnected' : status ? 'Connected' : '\u2014'} accent={unreachable ? 'error' : status ? 'success' : undefined} />
|
||||
<StatCard label="Version" value={status?.version ?? '\u2014'} />
|
||||
<StatCard label="Uptime" value={status?.uptime ?? '\u2014'} />
|
||||
</div>
|
||||
|
||||
{pipeline && (
|
||||
<div className={styles.pipelineCard}>
|
||||
<div className={styles.pipelineTitle}>Indexer Pipeline</div>
|
||||
<ProgressBar value={pipeline.maxQueueSize > 0 ? (pipeline.queueDepth / pipeline.maxQueueSize) * 100 : 0} />
|
||||
<div className={styles.pipelineMetrics}>
|
||||
<span>Queue: {pipeline.queueDepth}/{pipeline.maxQueueSize}</span>
|
||||
<span>Indexed: {pipeline.indexedCount.toLocaleString()}</span>
|
||||
<span>Failed: {pipeline.failedCount}</span>
|
||||
<span>Rate: {pipeline.indexingRate.toFixed(1)}/s</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{perf && (
|
||||
<div className={styles.statStrip}>
|
||||
<StatCard label="Select Queries" value={perf.queryCount.toLocaleString()} />
|
||||
<StatCard label="Insert Queries" value={perf.insertQueryCount.toLocaleString()} />
|
||||
<StatCard label="Memory" value={perf.memoryUsage} />
|
||||
<StatCard label="Rows Read" value={perf.readRows.toLocaleString()} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.tableSection}>
|
||||
<div className={styles.tableHeader}>
|
||||
<span className={styles.tableTitle}>Tables ({(tables || []).length})</span>
|
||||
</div>
|
||||
<DataTable
|
||||
columns={tableColumns}
|
||||
data={(tables || []).map((t: any) => ({ ...t, id: t.name }))}
|
||||
sortable
|
||||
pageSize={20}
|
||||
flush
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user