refactor(quality): Q13 前端巨型组件拆分 — UnifiedQueryPanel 682L→529L (-22%), 提取 constants + entry-mappers + 5 个 UI 子组件 (QueryControlRow/SecondaryToolbar/LogVolumeChart/ResultsTabs/QueryEmptyStates), 零逻辑变更

This commit is contained in:
attacker committed 2026-07-07 20:23:57 +08:00
1 parent b2e8fbbfc0
commit 8a11acd086
11 files changed
+660 -276

No files matched your search

@@ -0,0 +1,68 @@
// unified-query/QueryControlRow.tsx — 查询控制行(引擎徽标 + 输入框 + 查询按钮 + Live Tail)
import { Play, Loader2, Radio } from 'lucide-react';
import { QueryAutocompleteInput } from '../QueryAutocompleteInput';
import { useTranslation } from 'react-i18next';
interface QueryControlRowProps {
badge: { label: string; dotColor: string };
query: string;
onQueryChange: (q: string) => void;
effEngine: 'loki' | 'elasticsearch';
metaQueryPlaceholder: string;
labelNames: string[];
labelValues: string[];
mappingFields: string[];
onRequestLabelValues: (label: string) => void;
loading: boolean;
liveTail: boolean;
hasSource: boolean;
onRun: () => void;
onToggleLiveTail: () => void;
}
export function QueryControlRow({
badge, query, onQueryChange, effEngine, metaQueryPlaceholder,
labelNames, labelValues, mappingFields, onRequestLabelValues,
loading, liveTail, hasSource, onRun, onToggleLiveTail,
}: QueryControlRowProps) {
const { t } = useTranslation();
const canQuery = hasSource && query.trim().length > 0;
return (
<div className="flex items-center gap-2">
<div className="flex-1 flex items-center gap-2 min-w-0">
<div className="flex items-center gap-1.5 px-2.5 h-10 rounded flex-shrink-0" style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)' }}>
<span className="w-2 h-2 rounded-full" style={{ background: badge.dotColor }} />
<span className="text-[11px] font-semibold" style={{ color: badge.dotColor }}>{badge.label}</span>
</div>
<QueryAutocompleteInput
value={query}
onChange={onQueryChange}
engine={effEngine}
placeholder={metaQueryPlaceholder}
labelNames={labelNames}
labelValues={labelValues}
mappingFields={mappingFields}
onRequestLabelValues={onRequestLabelValues}
/>
<button onClick={onRun} disabled={loading || liveTail || !canQuery}
className="h-10 px-4 rounded text-xs font-medium text-white flex items-center gap-1.5 flex-shrink-0 transition-opacity hover:opacity-90 disabled:opacity-40 disabled:cursor-not-allowed"
style={{ background: '#22c55e' }}>
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Play className="h-4 w-4" />} {t('monitor.logPanel.query')}
</button>
<button
onClick={onToggleLiveTail}
disabled={!canQuery}
className="h-10 px-3 rounded text-xs flex items-center gap-1 flex-shrink-0"
style={{
border: `1px solid ${liveTail ? '#ef4444' : 'var(--dg-border)'}`,
color: liveTail ? '#ef4444' : 'var(--dg-text-secondary)',
background: liveTail ? 'rgba(239,68,68,0.1)' : 'var(--dg-bg-tertiary)',
}}
title={t('monitor.logPanel.liveTailTitle')}
>
<Radio className={`h-3.5 w-3.5 ${liveTail ? 'animate-pulse' : ''}`} /> Tail
</button>
</div>
</div>
);
}