Add logging with filters

This commit is contained in:
Twirre
2025-11-12 14:35:38 +00:00
committed by Gerla, J. (Justin)
parent b7eb0cb5ec
commit 231d7a5ba1
22 changed files with 1899 additions and 68 deletions

29
src/utils/cellStore.ts Normal file
View File

@@ -0,0 +1,29 @@
import {useSyncExternalStore} from "react";
type Unsub = () => void;
export type Cell<T> = {
get: () => T;
set: (next: T | ((prev: T) => T)) => void;
subscribe: (callback: () => void) => Unsub;
};
export function cell<T>(initial: T): Cell<T> {
let value = initial;
const listeners = new Set<() => void>();
return {
get: () => value,
set: (next) => {
value = typeof next === "function" ? (next as (v: T) => T)(value) : next;
for (const l of listeners) l();
},
subscribe: (callback) => {
listeners.add(callback);
return () => listeners.delete(callback);
},
};
}
export function useCell<T>(c: Cell<T>) {
return useSyncExternalStore(c.subscribe, c.get, c.get);
}

View File

@@ -0,0 +1,21 @@
/**
* Format a time duration like `HH:MM:SS.mmm`.
*
* @param durationMs time duration in milliseconds.
* @return formatted time string.
*/
export default function formatDuration(durationMs: number): string {
const isNegative = durationMs < 0;
if (isNegative) durationMs = -durationMs;
const hours = Math.floor(durationMs / 3600000);
const minutes = Math.floor((durationMs % 3600000) / 60000);
const seconds = Math.floor((durationMs % 60000) / 1000);
const milliseconds = Math.floor(durationMs % 1000);
return (isNegative ? '-' : '') +
`${hours.toString().padStart(2, '0')}:` +
`${minutes.toString().padStart(2, '0')}:` +
`${seconds.toString().padStart(2, '0')}.` +
`${milliseconds.toString().padStart(3, '0')}`;
}

View File

@@ -0,0 +1,24 @@
export type PriorityFilterPredicate<T> = {
priority: number;
predicate: (element: T) => boolean | null; // The predicate and its priority are ignored if it returns null.
}
/**
* Applies a list of priority predicates to an element. For all predicates that don't return null, if the ones with the highest level return true, then this function returns true.
* @param element The element to apply the predicates to.
* @param predicates The list of predicates to apply.
*/
export function applyPriorityPredicates<T>(element: T, predicates: PriorityFilterPredicate<T>[]): boolean {
let highestPriority = -1;
let highestKeep = true;
for (const predicate of predicates) {
if (predicate.priority >= highestPriority) {
const predicateKeep = predicate.predicate(element);
if (predicateKeep === null) continue; // This predicate doesn't care about the element, so skip it
if (predicate.priority > highestPriority) highestKeep = true;
highestPriority = predicate.priority;
highestKeep = highestKeep && predicateKeep;
}
}
return highestKeep;
}