| 1 | import type { ResourceTelemetryProcess, ResourceTelemetrySourceStatus } from "@t3tools/contracts"; |
| 2 | |
| 3 | function processIdentityKey(process: ResourceTelemetryProcess): string { |
| 4 | return `${process.identity.pid}:${process.identity.startTimeMs}`; |
| 5 | } |
| 6 | |
| 7 | export function visibleResourceTelemetryProcesses( |
| 8 | processes: ReadonlyArray<ResourceTelemetryProcess>, |
| 9 | collapsed: ReadonlySet<string>, |
| 10 | ): ReadonlyArray<ResourceTelemetryProcess> { |
| 11 | const childrenByParent = new Map<number, ResourceTelemetryProcess[]>(); |
| 12 | for (const process of processes) { |
| 13 | const children = childrenByParent.get(process.ppid) ?? []; |
| 14 | children.push(process); |
| 15 | childrenByParent.set(process.ppid, children); |
| 16 | } |
| 17 | |
| 18 | const hidden = new Set<string>(); |
| 19 | const hideDescendants = (pid: number): void => { |
| 20 | for (const child of childrenByParent.get(pid) ?? []) { |
| 21 | const key = processIdentityKey(child); |
| 22 | if (hidden.has(key)) continue; |
| 23 | hidden.add(key); |
| 24 | hideDescendants(child.identity.pid); |
| 25 | } |
| 26 | }; |
| 27 | for (const process of processes) { |
| 28 | if (collapsed.has(processIdentityKey(process))) { |
| 29 | hideDescendants(process.identity.pid); |
| 30 | } |
| 31 | } |
| 32 | return processes.filter((process) => !hidden.has(processIdentityKey(process))); |
| 33 | } |
| 34 | |
| 35 | export function shouldShowResourceMonitorRetry(input: { |
| 36 | readonly nativeStatus: ResourceTelemetrySourceStatus | null; |
| 37 | readonly error: string | null; |
| 38 | }): boolean { |
| 39 | return ( |
| 40 | (input.nativeStatus === null && input.error !== null) || |
| 41 | input.nativeStatus === "degraded" || |
| 42 | input.nativeStatus === "unavailable" || |
| 43 | input.nativeStatus === "stopped" |
| 44 | ); |
| 45 | } |
| 46 | |
| 47 | export function resourceHistoryBarHeight(input: { |
| 48 | readonly value: number; |
| 49 | readonly max: number; |
| 50 | readonly minimumVisiblePercent: number; |
| 51 | }): number { |
| 52 | if (input.value <= 0) return 0; |
| 53 | return Math.max(input.minimumVisiblePercent, (input.value / Math.max(1, input.max)) * 100); |
| 54 | } |
| 55 | |
| 56 | export function resourceHistoryCpuScaleMax( |
| 57 | buckets: ReadonlyArray<{ readonly avgCpuPercent: number }>, |
| 58 | ): number { |
| 59 | return Math.max(1, ...buckets.map((bucket) => bucket.avgCpuPercent)); |
| 60 | } |