mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-21 03:05:44 +00:00
Show macOS thermal pressure on Machines page
Render pressure-only thermal state in the standalone Machines temperature cell when no Celsius reading is available.
This commit is contained in:
@@ -89,6 +89,7 @@ import {
|
||||
getAgentMachineTemperatureCelsius,
|
||||
getAgentMachineTemperatureDetailSections,
|
||||
getAgentMachineTemperatureTitle,
|
||||
getAgentMachineThermalPressurePresentation,
|
||||
getNextAgentMachineSortState,
|
||||
sortAgentMachines,
|
||||
type AgentMachineColumn,
|
||||
@@ -172,10 +173,16 @@ const AgentMachineTemperatureCell: Component<{
|
||||
celsius: number | undefined;
|
||||
sections: AgentMachineTemperatureDetailSection[];
|
||||
title: string;
|
||||
thermalPressure?: {
|
||||
label: string;
|
||||
title: string;
|
||||
className: string;
|
||||
};
|
||||
}> = (props) => {
|
||||
const hasDetails = () => props.sections.length > 0;
|
||||
const positiveTemperature = () =>
|
||||
hasPositiveTemperature(props.celsius) ? props.celsius : undefined;
|
||||
const fallbackTitle = () => props.thermalPressure?.title ?? props.title;
|
||||
|
||||
return (
|
||||
<AgentMachineMetricTooltip
|
||||
@@ -184,10 +191,22 @@ const AgentMachineTemperatureCell: Component<{
|
||||
triggerClass="inline-flex min-w-[2.25rem] justify-end text-xs tabular-nums"
|
||||
tooltipClass="min-w-[190px] max-w-[300px] space-y-2"
|
||||
enabled={hasDetails()}
|
||||
ariaLabel={props.title || undefined}
|
||||
ariaLabel={fallbackTitle() || undefined}
|
||||
title={fallbackTitle()}
|
||||
maxWidth={320}
|
||||
trigger={
|
||||
<Show when={positiveTemperature()} fallback={<span class="text-muted">—</span>}>
|
||||
<Show
|
||||
when={positiveTemperature()}
|
||||
fallback={
|
||||
<Show when={props.thermalPressure} fallback={<span class="text-muted">—</span>}>
|
||||
{(thermal) => (
|
||||
<span class={`text-[11px] font-medium ${thermal().className}`}>
|
||||
{thermal().label}
|
||||
</span>
|
||||
)}
|
||||
</Show>
|
||||
}
|
||||
>
|
||||
{(value) => <TemperatureGauge value={value()} />}
|
||||
</Show>
|
||||
}
|
||||
@@ -1465,6 +1484,8 @@ export const AgentsMachinesTable: Component<{
|
||||
const temperatureSections = () =>
|
||||
getAgentMachineTemperatureDetailSections(machine);
|
||||
const temperatureTitle = () => getAgentMachineTemperatureTitle(machine);
|
||||
const thermalPressure = () =>
|
||||
getAgentMachineThermalPressurePresentation(machine);
|
||||
const isExpanded = () => drawer.isExpanded(machine);
|
||||
const detailRowId = () => drawer.detailRowId(machine);
|
||||
const agentMetadataId = () => agentMetadataIdFor(machine);
|
||||
@@ -1655,6 +1676,7 @@ export const AgentsMachinesTable: Component<{
|
||||
celsius={temperature()}
|
||||
sections={temperatureSections()}
|
||||
title={temperatureTitle()}
|
||||
thermalPressure={thermalPressure()}
|
||||
/>
|
||||
</TableCell>
|
||||
</Show>
|
||||
|
||||
@@ -898,4 +898,38 @@ describe('AgentsMachinesTable', () => {
|
||||
expect(screen.getByText('standby')).toBeInTheDocument();
|
||||
expect(screen.getByText('1400 RPM')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows thermal pressure when macOS reports no Celsius temperature', async () => {
|
||||
render(() => (
|
||||
<AgentsMachinesTable
|
||||
resources={[
|
||||
resource({
|
||||
id: 'mac-agent',
|
||||
name: 'RICHARD-MAC-MINI.local',
|
||||
temperature: undefined,
|
||||
agent: {
|
||||
agentVersion: 'v6.0.0',
|
||||
sensors: {
|
||||
thermalState: {
|
||||
source: 'pmset',
|
||||
pressure: 'nominal',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
]}
|
||||
emptyIcon={emptyIcon}
|
||||
emptyTitle="No machines"
|
||||
emptyDescription="Install Pulse Agent."
|
||||
/>
|
||||
));
|
||||
|
||||
const pressure = await screen.findByText('Nominal');
|
||||
|
||||
expect(pressure).toBeInTheDocument();
|
||||
expect(pressure.closest('[data-agent-machine-temperature-trigger="true"]')).toHaveAttribute(
|
||||
'title',
|
||||
'Thermal pressure nominal via pmset',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -135,6 +135,12 @@ export type AgentMachineTemperatureDetailSection = {
|
||||
rows: AgentMachineTemperatureDetailRow[];
|
||||
};
|
||||
|
||||
export type AgentMachineThermalPressurePresentation = {
|
||||
label: string;
|
||||
title: string;
|
||||
className: string;
|
||||
};
|
||||
|
||||
export type AgentMachineNetworkInterfaceDetail = {
|
||||
name: string;
|
||||
mac?: string;
|
||||
@@ -501,6 +507,35 @@ export const getAgentMachineTemperatureDetailSections = (
|
||||
export const getAgentMachineTemperatureTitle = (machine: Resource): string =>
|
||||
flattenTemperatureSections(getAgentMachineTemperatureDetailSections(machine));
|
||||
|
||||
export const getAgentMachineThermalPressurePresentation = (
|
||||
machine: Resource,
|
||||
): AgentMachineThermalPressurePresentation | undefined => {
|
||||
const pressure = asTrimmedString(machine.agent?.sensors?.thermalState?.pressure)?.toLowerCase();
|
||||
if (!pressure) return undefined;
|
||||
|
||||
const label =
|
||||
pressure === 'nominal' ? 'Nominal' : pressure === 'constrained' ? 'Constrained' : 'Unknown';
|
||||
const className =
|
||||
pressure === 'nominal'
|
||||
? 'text-emerald-600 dark:text-emerald-400'
|
||||
: pressure === 'constrained'
|
||||
? 'text-amber-600 dark:text-amber-400'
|
||||
: 'text-muted';
|
||||
const source = asTrimmedString(machine.agent?.sensors?.thermalState?.source);
|
||||
const limits = Object.entries(machine.agent?.sensors?.thermalState?.limitsPercent ?? {})
|
||||
.filter(([, value]) => Number.isFinite(value) && value < 100)
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([key, value]) => `${key.replace(/_/g, ' ')} ${Math.round(value)}%`);
|
||||
const sourceSummary = source ? ` via ${source}` : '';
|
||||
const limitSummary = limits.length > 0 ? `; limits: ${limits.join(', ')}` : '';
|
||||
|
||||
return {
|
||||
label,
|
||||
className,
|
||||
title: `Thermal pressure ${label.toLowerCase()}${sourceSummary}${limitSummary}`,
|
||||
};
|
||||
};
|
||||
|
||||
export const timestampMillisFrom = (
|
||||
value: number | string | Date | undefined,
|
||||
): number | undefined => {
|
||||
|
||||
Reference in New Issue
Block a user