mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
feat(ui): hide dashboard self-polling internals via default filter
On real backend, the logs page was drowning in dashboard self-polling noise — every `/api/logs` poll emitted a 149-stage `web-server:http` trace, burying real provider activity. - New workspace state `hideDashboardInternals` defaults ON. Entries whose `source` matches `/^web-server:/i` are filtered client-side before they reach the list. - Toggle exposed in advanced filters as a labelled checkbox/switch with a one-line description, so users can opt in to see internals when debugging the dashboard itself. - `clearAdvancedFilters` resets the toggle back to ON to keep the default signal-clean experience. - Header stat strip (entries / traces / errors) wired through the shell. Backend-side `web-server:*` instrumentation stays intact (still useful for ops debugging) — just hidden from the user-facing log feed by default. Refs #1138, #1141, #1142
This commit is contained in:
@@ -44,6 +44,9 @@ export interface LogsFiltersProps {
|
||||
onRequestIdChange?: (v: string) => void;
|
||||
timeWindow?: LogsTimeWindow;
|
||||
onTimeWindowChange?: (v: LogsTimeWindow) => void;
|
||||
/** When true, hides entries from `web-server:*` sources. Default ON. */
|
||||
hideDashboardInternals?: boolean;
|
||||
onHideDashboardInternalsChange?: (next: boolean) => void;
|
||||
onClearAll?: () => void;
|
||||
}
|
||||
|
||||
@@ -88,6 +91,8 @@ export function LogsFilters({
|
||||
onRequestIdChange,
|
||||
timeWindow = 'all',
|
||||
onTimeWindowChange,
|
||||
hideDashboardInternals = true,
|
||||
onHideDashboardInternalsChange,
|
||||
onClearAll,
|
||||
}: LogsFiltersProps) {
|
||||
const [advancedOpen, setAdvancedOpen] = useState(false);
|
||||
@@ -312,6 +317,31 @@ export function LogsFilters({
|
||||
</Select>
|
||||
</div>
|
||||
) : null}
|
||||
{onHideDashboardInternalsChange ? (
|
||||
<div className="flex items-start justify-between gap-3 rounded border border-border/60 bg-muted/20 p-2">
|
||||
<div className="space-y-0.5">
|
||||
<Label
|
||||
htmlFor="logs-hide-internals"
|
||||
className="block text-[12px] font-medium text-foreground"
|
||||
>
|
||||
Hide dashboard internals
|
||||
</Label>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
Suppress <code className="rounded bg-background px-1">web-server:*</code>{' '}
|
||||
self-polling.
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
id="logs-hide-internals"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
checked={hideDashboardInternals}
|
||||
onChange={(e) => onHideDashboardInternalsChange(e.target.checked)}
|
||||
className={cn('mt-0.5 h-4 w-4 cursor-pointer accent-foreground', FOCUS_RING)}
|
||||
aria-label="Hide dashboard internals"
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
|
||||
|
||||
@@ -137,6 +137,18 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) {
|
||||
[workspace.entriesQuery.data]
|
||||
);
|
||||
|
||||
// Derive header stat strip values once per data refetch.
|
||||
const headerStats = useMemo(() => {
|
||||
const data = workspace.entriesQuery.data ?? [];
|
||||
const requestIds = new Set<string>();
|
||||
let errors = 0;
|
||||
for (const entry of data) {
|
||||
if (entry.requestId) requestIds.add(entry.requestId);
|
||||
if (entry.level === 'error') errors += 1;
|
||||
}
|
||||
return { entries: data.length, traces: requestIds.size, errors };
|
||||
}, [workspace.entriesQuery.data]);
|
||||
|
||||
const focusSearch = useCallback(() => {
|
||||
const input = document.getElementById('logs-search') as HTMLInputElement | null;
|
||||
if (input) {
|
||||
@@ -180,6 +192,8 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) {
|
||||
onRequestIdChange={workspace.setRequestIdFilter}
|
||||
timeWindow={workspace.timeWindow}
|
||||
onTimeWindowChange={workspace.setTimeWindow}
|
||||
hideDashboardInternals={workspace.hideDashboardInternals}
|
||||
onHideDashboardInternalsChange={workspace.setHideDashboardInternals}
|
||||
onClearAll={workspace.clearAdvancedFilters}
|
||||
/>
|
||||
);
|
||||
@@ -228,6 +242,7 @@ export function LogsShell({ workspace, updateConfig }: LogsShellProps) {
|
||||
isFetching={workspace.entriesQuery.isFetching || workspace.sourcesQuery.isFetching}
|
||||
hasError={Boolean(workspace.entriesQuery.error)}
|
||||
capturedCount={workspace.entriesQuery.data?.length ?? 0}
|
||||
stats={headerStats}
|
||||
onRefresh={handleRefresh}
|
||||
onOpenSettings={openSettings}
|
||||
onOpenShortcuts={() => setShortcutsOpen(true)}
|
||||
|
||||
@@ -116,6 +116,10 @@ export function useLogsWorkspace() {
|
||||
const [limit, setLimit] = useState(DEFAULT_LIMIT);
|
||||
const [selectedEntryId, setSelectedEntryId] = useState<string | null>(null);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
// Default ON: dashboard self-polling generates 100s of identical entries
|
||||
// per refresh which drown out real provider activity. Users can opt in to
|
||||
// see internals via the advanced filter toggle.
|
||||
const [hideDashboardInternals, setHideDashboardInternals] = useState(true);
|
||||
const frozenIdsRef = useRef<Set<string>>(new Set());
|
||||
|
||||
const deferredSearch = useDeferredValue(search.trim());
|
||||
@@ -151,6 +155,7 @@ export function useLogsWorkspace() {
|
||||
debouncedRequestId,
|
||||
timeWindow,
|
||||
limit,
|
||||
hideDashboardInternals ? 'hide-internals' : 'show-internals',
|
||||
mockEnabled ? 'mock' : 'live',
|
||||
],
|
||||
queryFn: async () => {
|
||||
@@ -191,6 +196,9 @@ export function useLogsWorkspace() {
|
||||
const ts = Date.parse(entry.timestamp);
|
||||
if (Number.isFinite(ts) && now - ts > cutoffMs) return false;
|
||||
}
|
||||
// Hide dashboard self-polling unless user opted in. Preserves the
|
||||
// signal-to-noise ratio for fresh-load investigations.
|
||||
if (hideDashboardInternals && /^web-server:/i.test(entry.source)) return false;
|
||||
return true;
|
||||
});
|
||||
const head = filtered[0];
|
||||
@@ -265,6 +273,7 @@ export function useLogsWorkspace() {
|
||||
setStageFilter('');
|
||||
setRequestIdFilter('');
|
||||
setTimeWindow('all');
|
||||
setHideDashboardInternals(true);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
@@ -285,6 +294,8 @@ export function useLogsWorkspace() {
|
||||
setRequestIdFilter,
|
||||
timeWindow,
|
||||
setTimeWindow,
|
||||
hideDashboardInternals,
|
||||
setHideDashboardInternals,
|
||||
limit,
|
||||
setLimit,
|
||||
selectedEntryId: activeSelectedEntryId,
|
||||
|
||||
Reference in New Issue
Block a user