mirror of
https://github.com/cpvalente/ontime.git
synced 2026-07-26 10:38:55 +00:00
perf(cuesheet): add temporary first-render metrics scaffold
Adds a dev-only, self-contained instrumentation module under common/devtools/cuesheet-metrics to measure the first-render (mount) cost of virtualised cuesheet rows, so scroll-performance changes can be backed by before/after numbers. - Console-only API on window.__cuesheetPerf (deterministic scroll benchmark + manual start/stop), gated by isDev && ?perf=1, runtime-inert in prod. - Whole-row mount probe plus per-subsystem attribution: colour calc, getVisibleCells, AutoTextarea autosize, Tooltip portal mount, useReactiveTextInput hotkey-handler init; FPS/long-frame timing. - All edits to existing files tagged // PERF-METRICS for a one-pass teardown. Temporary: to be deleted once the optimizations are proven.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import autosize from 'autosize/dist/autosize';
|
||||
import { RefObject, useEffect } from 'react';
|
||||
|
||||
import { timeSync } from '../../../devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
|
||||
import Textarea, { type TextareaProps } from '../textarea/Textarea';
|
||||
|
||||
interface AutoTextAreaProps extends TextareaProps {
|
||||
@@ -15,7 +16,7 @@ export function AutoTextarea({ value, inputref, ...textAreaProps }: AutoTextArea
|
||||
// when the value changes, we use the ref to reapply autosize
|
||||
useEffect(() => {
|
||||
const node = inputref.current;
|
||||
autosize(inputref.current);
|
||||
timeSync('cell.autosize', () => autosize(inputref.current)); // PERF-METRICS
|
||||
|
||||
return () => {
|
||||
autosize.destroy(node);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { HotkeyItem, getHotkeyHandler } from '@mantine/hooks';
|
||||
import { ChangeEvent, KeyboardEvent, RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { timeSync } from '../../../devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
|
||||
|
||||
interface UseReactiveTextInputReturn {
|
||||
value: string;
|
||||
onChange: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
||||
@@ -95,7 +97,7 @@ export default function useReactiveTextInput(
|
||||
setTimeout(() => ref.current?.blur()); // Immediate timeout to ensure text is set before blurring
|
||||
}, [initialText, options, ref]);
|
||||
|
||||
const keyHandler = useMemo(() => {
|
||||
const keyHandler = useMemo(() => timeSync('cell.reactiveInputInit', () => { // PERF-METRICS
|
||||
const hotKeys: HotkeyItem[] = [
|
||||
[
|
||||
'Escape',
|
||||
@@ -155,7 +157,7 @@ export default function useReactiveTextInput(
|
||||
|
||||
hotKeyHandler(event);
|
||||
};
|
||||
}, [handleEscape, handleSubmit, options?.submitOnCtrlEnter, options?.submitOnEnter, options?.submitOnTab, text]);
|
||||
}), [handleEscape, handleSubmit, options?.submitOnCtrlEnter, options?.submitOnEnter, options?.submitOnTab, text]); // PERF-METRICS
|
||||
|
||||
return {
|
||||
value: text,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
import { useMountProbe } from '../../devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
|
||||
|
||||
import style from './Tooltip.module.scss';
|
||||
|
||||
interface TooltipProps extends BaseTooltip.Trigger.Props {
|
||||
@@ -8,6 +10,7 @@ interface TooltipProps extends BaseTooltip.Trigger.Props {
|
||||
}
|
||||
|
||||
export default function Tooltip({ text, children, ...triggerProps }: PropsWithChildren<TooltipProps>) {
|
||||
useMountProbe('cell.tooltip'); // PERF-METRICS
|
||||
return (
|
||||
<BaseTooltip.Root>
|
||||
<BaseTooltip.Trigger {...triggerProps}>{children}</BaseTooltip.Trigger>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# cuesheet-metrics (TEMPORARY)
|
||||
|
||||
Dev-only instrumentation to measure the **first-render (mount) cost of virtualised cuesheet
|
||||
rows**, so the scroll-performance optimizations can be supported by before/after numbers.
|
||||
|
||||
> This whole directory is temporary and must be deleted once the optimizations are proven.
|
||||
> Every edit it makes to existing files is tagged `// PERF-METRICS`.
|
||||
|
||||
## Enable
|
||||
|
||||
Open the cuesheet in a **dev build** with the `?perf=1` query param:
|
||||
|
||||
```
|
||||
http://localhost:3000/cuesheet?perf=1
|
||||
```
|
||||
|
||||
Nothing is collected and nothing is exposed unless both conditions hold (`isDev && ?perf=1`).
|
||||
In production builds `isDev` is `false`, so all recording paths are runtime-inert.
|
||||
|
||||
## Measure
|
||||
|
||||
A console API is exposed on `window.__cuesheetPerf`:
|
||||
|
||||
- `runScrollBenchmark(options?)` — deterministic, hands-off scroll from `fromIndex` to
|
||||
`toIndex` and back, then prints the result. Use the same options before/after a change so
|
||||
numbers are comparable. Options: `{ fromIndex=0, toIndex=200, stride=8, stepMs=16 }`.
|
||||
- `start()` / `stop()` — begin a manual session, scroll by hand, then stop to print.
|
||||
- `dump()` / `reset()`.
|
||||
|
||||
To emulate a low-end device, set Chrome DevTools → Performance → CPU 4×–6× slowdown, then run
|
||||
the benchmark 3× and compare medians.
|
||||
|
||||
## What is reported
|
||||
|
||||
- **Summary:** rows mounted, frames, long frames (>~25ms), avg/min FPS, worst frame ms.
|
||||
- **Marks** (count / avg ms / max ms / total ms):
|
||||
- `EventRow.mount` — whole-row mount time (render-start → post-commit layout)
|
||||
- `cell.tooltip.mount` — mount of a delay-indicator tooltip subtree (portal/positioner)
|
||||
- `row.colourCalc` — per-row colour-accessibility computation
|
||||
- `row.getVisibleCells` — react-table visible-cell expansion
|
||||
- `cell.autosize` — `AutoTextarea` autosize + MutationObserver setup
|
||||
- `cell.reactiveInputInit` — `useReactiveTextInput` hotkey-handler construction
|
||||
- `longtask` — main-thread long tasks captured during the session (where supported)
|
||||
|
||||
## Teardown
|
||||
|
||||
1. `rg "PERF-METRICS" apps/client/src` → revert each tagged line in the existing files
|
||||
(`CuesheetTable.tsx`, `EventRow.tsx`, `AutoTextarea.tsx`, `Tooltip.tsx`,
|
||||
`useReactiveTextInput.tsx`) back to its original body.
|
||||
2. Delete this directory.
|
||||
3. `rg "cuesheet-metrics|__cuesheetPerf" apps/client/src` → must be empty.
|
||||
4. `pnpm typecheck && pnpm test:pipeline && pnpm build`.
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold (delete with this directory).
|
||||
*
|
||||
* A deterministic, hands-off scroll runner so before/after numbers are comparable. Scrolls the
|
||||
* virtualised table from `fromIndex` to `toIndex` and back in fixed index strides, under an
|
||||
* active frame-timing session, then dumps the result.
|
||||
*/
|
||||
import type { RefObject } from 'react';
|
||||
import type { TableVirtuosoHandle } from 'react-virtuoso';
|
||||
|
||||
import { PERF_ENABLED } from './perfConfig';
|
||||
import { dump, endSession, startSession } from './perfStore';
|
||||
import { startFpsMonitor, stopFpsMonitor } from './scrollFpsMonitor';
|
||||
|
||||
export interface BenchmarkOptions {
|
||||
fromIndex?: number;
|
||||
toIndex?: number;
|
||||
/** Indices advanced per step. */
|
||||
stride?: number;
|
||||
/** Delay between steps, ms. */
|
||||
stepMs?: number;
|
||||
}
|
||||
|
||||
export async function runScrollBenchmark(
|
||||
virtuosoRef: RefObject<TableVirtuosoHandle | null>,
|
||||
options: BenchmarkOptions = {},
|
||||
): Promise<void> {
|
||||
if (!PERF_ENABLED) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('[cuesheet-perf] disabled — open the cuesheet with ?perf=1 in a dev build.');
|
||||
return;
|
||||
}
|
||||
const handle = virtuosoRef.current;
|
||||
if (!handle) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('[cuesheet-perf] virtuoso handle not ready.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { fromIndex = 0, toIndex = 200, stride = 8, stepMs = 16 } = options;
|
||||
|
||||
startSession();
|
||||
startFpsMonitor();
|
||||
|
||||
await scrollThrough(handle, fromIndex, toIndex, stride, stepMs);
|
||||
await scrollThrough(handle, toIndex, fromIndex, stride, stepMs);
|
||||
|
||||
stopFpsMonitor();
|
||||
endSession();
|
||||
dump();
|
||||
}
|
||||
|
||||
function scrollThrough(
|
||||
handle: TableVirtuosoHandle,
|
||||
from: number,
|
||||
to: number,
|
||||
stride: number,
|
||||
stepMs: number,
|
||||
): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const dir = to >= from ? 1 : -1;
|
||||
let current = from;
|
||||
|
||||
const step = () => {
|
||||
handle.scrollToIndex({ index: current, behavior: 'auto', align: 'start' });
|
||||
|
||||
if (current === to) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
current += stride * dir;
|
||||
if ((dir > 0 && current > to) || (dir < 0 && current < to)) {
|
||||
current = to;
|
||||
}
|
||||
setTimeout(step, stepMs);
|
||||
};
|
||||
|
||||
step();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold.
|
||||
*
|
||||
* This whole directory (common/devtools/cuesheet-metrics) is temporary and is meant to be
|
||||
* deleted once the first-render optimizations are proven. See the perf investigation plan.
|
||||
*
|
||||
* Gates all instrumentation: enabled only in a dev build AND when the page is opened with
|
||||
* `?perf=1`. Because `isDev` resolves to `import.meta.env.DEV`, this is `false` in production,
|
||||
* so every recording path stays runtime-inert there (the guarded code may still be present in
|
||||
* the bundle — it is never executed, and the whole scaffold is removed at teardown).
|
||||
*/
|
||||
import { isDev } from '../../../externals';
|
||||
|
||||
function readPerfParam(): boolean {
|
||||
try {
|
||||
return new URLSearchParams(window.location.search).get('perf') === '1';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const PERF_ENABLED = isDev && readPerfParam();
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold (delete with this directory).
|
||||
*
|
||||
* Plain module singleton (no zustand): the metrics are surfaced via the console only, so there
|
||||
* is no React subscriber that would justify a reactive store. Everything here is a no-op unless
|
||||
* a session is running, and call sites are additionally gated by PERF_ENABLED.
|
||||
*/
|
||||
|
||||
/** A frame slower than ~1.5 frames at 60fps is counted as a "long frame". */
|
||||
const LONG_FRAME_MS = (1000 / 60) * 1.5;
|
||||
|
||||
interface MarkStat {
|
||||
count: number;
|
||||
totalMs: number;
|
||||
maxMs: number;
|
||||
}
|
||||
|
||||
interface PerfState {
|
||||
running: boolean;
|
||||
marks: Record<string, MarkStat>;
|
||||
rowsMounted: number;
|
||||
frameCount: number;
|
||||
totalFrameMs: number;
|
||||
maxFrameMs: number;
|
||||
longFrames: number;
|
||||
}
|
||||
|
||||
function createState(): PerfState {
|
||||
return {
|
||||
running: false,
|
||||
marks: {},
|
||||
rowsMounted: 0,
|
||||
frameCount: 0,
|
||||
totalFrameMs: 0,
|
||||
maxFrameMs: 0,
|
||||
longFrames: 0,
|
||||
};
|
||||
}
|
||||
|
||||
let state = createState();
|
||||
|
||||
export function isRunning(): boolean {
|
||||
return state.running;
|
||||
}
|
||||
|
||||
export function startSession(): void {
|
||||
state = createState();
|
||||
state.running = true;
|
||||
}
|
||||
|
||||
export function endSession(): void {
|
||||
state.running = false;
|
||||
}
|
||||
|
||||
export function reset(): void {
|
||||
state = createState();
|
||||
}
|
||||
|
||||
export function recordMark(name: string, ms: number): void {
|
||||
if (!state.running) return;
|
||||
const mark = state.marks[name] ?? { count: 0, totalMs: 0, maxMs: 0 };
|
||||
mark.count += 1;
|
||||
mark.totalMs += ms;
|
||||
mark.maxMs = Math.max(mark.maxMs, ms);
|
||||
state.marks[name] = mark;
|
||||
}
|
||||
|
||||
export function recordRowMount(): void {
|
||||
if (!state.running) return;
|
||||
state.rowsMounted += 1;
|
||||
}
|
||||
|
||||
export function recordFrame(deltaMs: number): void {
|
||||
if (!state.running) return;
|
||||
state.frameCount += 1;
|
||||
state.totalFrameMs += deltaMs;
|
||||
state.maxFrameMs = Math.max(state.maxFrameMs, deltaMs);
|
||||
if (deltaMs > LONG_FRAME_MS) {
|
||||
state.longFrames += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Dumps the collected metrics to the console as tables. */
|
||||
export function dump(): void {
|
||||
const markRows = Object.entries(state.marks)
|
||||
.map(([name, m]) => ({
|
||||
mark: name,
|
||||
count: m.count,
|
||||
avgMs: round(m.totalMs / m.count),
|
||||
maxMs: round(m.maxMs),
|
||||
totalMs: round(m.totalMs),
|
||||
}))
|
||||
.sort((a, b) => b.totalMs - a.totalMs);
|
||||
|
||||
const avgFps = state.totalFrameMs > 0 ? round((state.frameCount * 1000) / state.totalFrameMs) : 0;
|
||||
const minFps = state.maxFrameMs > 0 ? round(1000 / state.maxFrameMs) : 0;
|
||||
|
||||
const summary = {
|
||||
rowsMounted: state.rowsMounted,
|
||||
frames: state.frameCount,
|
||||
longFrames: state.longFrames,
|
||||
avgFps,
|
||||
minFps,
|
||||
maxFrameMs: round(state.maxFrameMs),
|
||||
};
|
||||
|
||||
/* eslint-disable no-console */
|
||||
console.group('[cuesheet-perf] benchmark result');
|
||||
console.table(summary);
|
||||
console.table(markRows);
|
||||
console.groupEnd();
|
||||
/* eslint-enable no-console */
|
||||
}
|
||||
|
||||
function round(value: number): number {
|
||||
return Math.round(value * 100) / 100;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold (delete with this directory).
|
||||
*
|
||||
* Drives a requestAnimationFrame loop while a session is running to capture frame timing
|
||||
* (FPS / long-frame count) and, where supported, records main-thread long tasks.
|
||||
*/
|
||||
import { PERF_ENABLED } from './perfConfig';
|
||||
import { recordFrame, recordMark } from './perfStore';
|
||||
|
||||
let rafId: number | null = null;
|
||||
let lastFrame = 0;
|
||||
let observer: PerformanceObserver | null = null;
|
||||
|
||||
export function startFpsMonitor(): void {
|
||||
if (!PERF_ENABLED || rafId !== null) return;
|
||||
|
||||
lastFrame = performance.now();
|
||||
const tick = (now: number) => {
|
||||
recordFrame(now - lastFrame);
|
||||
lastFrame = now;
|
||||
rafId = requestAnimationFrame(tick);
|
||||
};
|
||||
rafId = requestAnimationFrame(tick);
|
||||
|
||||
if (typeof PerformanceObserver !== 'undefined') {
|
||||
try {
|
||||
observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
recordMark('longtask', entry.duration);
|
||||
}
|
||||
});
|
||||
observer.observe({ entryTypes: ['longtask'] });
|
||||
} catch {
|
||||
observer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function stopFpsMonitor(): void {
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = null;
|
||||
}
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
observer = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold (delete with this directory).
|
||||
*
|
||||
* Wires the metrics scaffold into the cuesheet table. When enabled (`?perf=1` in a dev build) it
|
||||
* exposes a console API on `window.__cuesheetPerf` and is otherwise an inert no-op.
|
||||
*
|
||||
* __cuesheetPerf.runScrollBenchmark() // deterministic scroll, dumps a comparable result
|
||||
* __cuesheetPerf.start() // begin a manual session (then scroll by hand)
|
||||
* __cuesheetPerf.stop() // end the manual session and dump
|
||||
*/
|
||||
import { useEffect, type RefObject } from 'react';
|
||||
import type { TableVirtuosoHandle } from 'react-virtuoso';
|
||||
|
||||
import { runScrollBenchmark, type BenchmarkOptions } from './benchmark';
|
||||
import { PERF_ENABLED } from './perfConfig';
|
||||
import { dump, endSession, reset, startSession } from './perfStore';
|
||||
import { startFpsMonitor, stopFpsMonitor } from './scrollFpsMonitor';
|
||||
|
||||
export function useCuesheetPerf(virtuosoRef: RefObject<TableVirtuosoHandle | null>): void {
|
||||
useEffect(() => {
|
||||
if (!PERF_ENABLED) return;
|
||||
|
||||
const api = {
|
||||
runScrollBenchmark: (options?: BenchmarkOptions) => runScrollBenchmark(virtuosoRef, options),
|
||||
start: () => {
|
||||
startSession();
|
||||
startFpsMonitor();
|
||||
},
|
||||
stop: () => {
|
||||
stopFpsMonitor();
|
||||
endSession();
|
||||
dump();
|
||||
},
|
||||
dump,
|
||||
reset,
|
||||
};
|
||||
|
||||
(window as unknown as { __cuesheetPerf?: typeof api }).__cuesheetPerf = api;
|
||||
// eslint-disable-next-line no-console
|
||||
console.info('[cuesheet-perf] enabled. window.__cuesheetPerf = { runScrollBenchmark, start, stop, dump, reset }');
|
||||
|
||||
return () => {
|
||||
stopFpsMonitor();
|
||||
delete (window as unknown as { __cuesheetPerf?: typeof api }).__cuesheetPerf;
|
||||
};
|
||||
}, [virtuosoRef]);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* PERF-METRICS — temporary cuesheet scroll-performance scaffold (delete with this directory).
|
||||
*
|
||||
* Lightweight timing helpers. All no-op when instrumentation is disabled so the call sites in
|
||||
* shared components stay cheap (and fold away in production builds).
|
||||
*/
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
|
||||
import { PERF_ENABLED } from './perfConfig';
|
||||
import { recordMark, recordRowMount } from './perfStore';
|
||||
|
||||
/** Times the synchronous `fn`, records the duration under `name`, and returns its result. */
|
||||
export function timeSync<T>(name: string, fn: () => T): T {
|
||||
if (!PERF_ENABLED) return fn();
|
||||
const start = performance.now();
|
||||
try {
|
||||
return fn();
|
||||
} finally {
|
||||
recordMark(name, performance.now() - start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the mount cost of a component (render-start → post-commit layout) and records it
|
||||
* under `${name}.mount`. Used on EventRow and on the Tooltip subtree to attribute per-row
|
||||
* first-render cost. Pass `countAsRow` on the row probe so only rows feed the rows-mounted tally.
|
||||
*/
|
||||
export function useMountProbe(name: string, countAsRow = false): void {
|
||||
const renderStart = useRef(PERF_ENABLED ? performance.now() : 0);
|
||||
useLayoutEffect(() => {
|
||||
if (!PERF_ENABLED) return;
|
||||
recordMark(`${name}.mount`, performance.now() - renderStart.current);
|
||||
if (countAsRow) {
|
||||
recordRowMount();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- mount-only probe
|
||||
}, []);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import EmptyPage from '../../../common/components/state/EmptyPage';
|
||||
import EmptyTableBody from '../../../common/components/state/EmptyTableBody';
|
||||
import { useEntryActionsContext } from '../../../common/context/EntryActionsContext';
|
||||
import { useCuesheetPerf } from '../../../common/devtools/cuesheet-metrics/useCuesheetPerf'; // PERF-METRICS
|
||||
import type { RundownSource } from '../../../common/hooks-query/useScopedRundown';
|
||||
import type { ExtendedEntry } from '../../../common/utils/rundownMetadata';
|
||||
import { usePersistedRundownOptions } from '../../../features/rundown/rundown.options';
|
||||
@@ -72,6 +73,7 @@ export default function CuesheetTable({
|
||||
const setScrollHandler = useEventSelection((state) => state.setScrollHandler);
|
||||
|
||||
const virtuosoRef = useRef<TableVirtuosoHandle | null>(null);
|
||||
useCuesheetPerf(virtuosoRef); // PERF-METRICS
|
||||
const { listeners } = useTableNav();
|
||||
|
||||
const meta = useMemo(
|
||||
|
||||
+21
-18
@@ -5,6 +5,7 @@ import { CSSProperties, memo, useMemo } from 'react';
|
||||
import { IoEllipsisHorizontal } from 'react-icons/io5';
|
||||
|
||||
import IconButton from '../../../../common/components/buttons/IconButton';
|
||||
import { timeSync, useMountProbe } from '../../../../common/devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
|
||||
import type { ExtendedEntry } from '../../../../common/utils/rundownMetadata';
|
||||
import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils';
|
||||
import { AppMode } from '../../../../ontimeConfig';
|
||||
@@ -56,25 +57,29 @@ function EventRow({
|
||||
|
||||
const openMenu = useCuesheetTableMenu((store) => store.openMenu);
|
||||
|
||||
useMountProbe('EventRow', true); // PERF-METRICS
|
||||
|
||||
const { rowBgColour, backgroundColor, mutedText } = useMemo(() => {
|
||||
const accessible = getAccessibleColour(colour);
|
||||
const tmpColour = cssOrHexToColour(accessible.color) as RGBColour;
|
||||
return timeSync('row.colourCalc', () => { // PERF-METRICS
|
||||
const accessible = getAccessibleColour(colour);
|
||||
const tmpColour = cssOrHexToColour(accessible.color) as RGBColour;
|
||||
|
||||
let rowBgColour: string | undefined;
|
||||
if (isLoaded) {
|
||||
rowBgColour = '#087A27'; // $active-green
|
||||
} else if (colour) {
|
||||
const accessibleBg = cssOrHexToColour(accessible.backgroundColor);
|
||||
if (accessibleBg !== null) {
|
||||
rowBgColour = colourToHex({ ...accessibleBg, alpha: accessibleBg.alpha * 0.25 });
|
||||
let rowBgColour: string | undefined;
|
||||
if (isLoaded) {
|
||||
rowBgColour = '#087A27'; // $active-green
|
||||
} else if (colour) {
|
||||
const accessibleBg = cssOrHexToColour(accessible.backgroundColor);
|
||||
if (accessibleBg !== null) {
|
||||
rowBgColour = colourToHex({ ...accessibleBg, alpha: accessibleBg.alpha * 0.25 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rowBgColour,
|
||||
backgroundColor: accessible.backgroundColor,
|
||||
mutedText: colourToHex({ ...tmpColour, alpha: tmpColour.alpha * 0.8 }),
|
||||
};
|
||||
return {
|
||||
rowBgColour,
|
||||
backgroundColor: accessible.backgroundColor,
|
||||
mutedText: colourToHex({ ...tmpColour, alpha: tmpColour.alpha * 0.8 }),
|
||||
};
|
||||
}); // PERF-METRICS
|
||||
}, [colour, isLoaded]);
|
||||
|
||||
return (
|
||||
@@ -117,9 +122,7 @@ function EventRow({
|
||||
{eventIndex}
|
||||
</td>
|
||||
)}
|
||||
{table
|
||||
.getRow(rowId)
|
||||
.getVisibleCells()
|
||||
{timeSync('row.getVisibleCells', () => table.getRow(rowId).getVisibleCells()) // PERF-METRICS
|
||||
.map((cell) => {
|
||||
return (
|
||||
<td
|
||||
|
||||
Reference in New Issue
Block a user