feat(dashboard): add performance and operations slices

This commit is contained in:
jjbrunton committed 2026-08-08 15:10:52 +01:00
1 parent 20fa83f245
commit 5917b63755
13 files changed
+1059

No files matched your search

@@ -0,0 +1,106 @@
export type ConsoleLevel = 'debug' | 'info' | 'warn' | 'error';
export type ConsoleLevelFilter = 'all' | ConsoleLevel;
export interface ConsoleEntry {
id: string;
occurredAt: string;
level: ConsoleLevel;
message: string;
data?: unknown;
}
export interface LiveConsoleState {
capacity: number;
entries: readonly ConsoleEntry[];
pendingEntries: readonly ConsoleEntry[];
isPaused: boolean;
isAutoScrollEnabled: boolean;
level: ConsoleLevelFilter;
search: string;
}
export type LiveConsoleAction =
| { type: 'append'; entry: ConsoleEntry }
| { type: 'set-paused'; paused: boolean }
| { type: 'set-auto-scroll'; enabled: boolean }
| { type: 'set-level'; level: ConsoleLevelFilter }
| { type: 'set-search'; search: string };
function boundedAppend(
entries: readonly ConsoleEntry[],
entry: ConsoleEntry,
capacity: number,
): readonly ConsoleEntry[] {
if (entries.some(({ id }) => id === entry.id)) return entries;
return [...entries, entry].slice(-capacity);
}
export function createLiveConsoleState(capacity = 500): LiveConsoleState {
if (!Number.isInteger(capacity) || capacity <= 0) {
throw new RangeError('capacity must be a positive integer');
}
return {
capacity,
entries: [],
pendingEntries: [],
isPaused: false,
isAutoScrollEnabled: true,
level: 'all',
search: '',
};
}
export function reduceLiveConsoleState(
state: LiveConsoleState,
action: LiveConsoleAction,
): LiveConsoleState {
switch (action.type) {
case 'append': {
if (
state.entries.some(({ id }) => id === action.entry.id) ||
state.pendingEntries.some(({ id }) => id === action.entry.id)
) return state;
return state.isPaused
? { ...state, pendingEntries: boundedAppend(state.pendingEntries, action.entry, state.capacity) }
: { ...state, entries: boundedAppend(state.entries, action.entry, state.capacity) };
}
case 'set-paused':
if (action.paused === state.isPaused) return state;
return action.paused
? { ...state, isPaused: true }
: {
...state,
isPaused: false,
entries: [...state.entries, ...state.pendingEntries].slice(-state.capacity),
pendingEntries: [],
};
case 'set-auto-scroll':
return { ...state, isAutoScrollEnabled: action.enabled };
case 'set-level':
return { ...state, level: action.level };
case 'set-search':
return { ...state, search: action.search };
}
}
function searchableData(data: unknown): string {
if (data === undefined) return '';
try {
return JSON.stringify(data);
} catch {
return '';
}
}
export function selectVisibleConsoleEntries(
state: LiveConsoleState,
): readonly ConsoleEntry[] {
const search = state.search.trim().toLocaleLowerCase();
return state.entries.filter((entry) => {
if (state.level !== 'all' && entry.level !== state.level) return false;
if (search.length === 0) return true;
return `${entry.message} ${searchableData(entry.data)}`
.toLocaleLowerCase()
.includes(search);
});
}