mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 18:45:53 +00:00
Add explicit per-metric off toggles to alert threshold editors
Disabling one metric for one resource required knowing to type -1 into the override editor (the alert engine treats trigger <= 0 as disabled), and the global-defaults row could only re-enable a disabled metric by click, not disable one. Add an On/Off badge next to the threshold input in the override row editor (desktop and mobile), in the global-defaults row (desktop and mobile), and in the bulk edit dialog, mirroring the existing Backup/Snapshot StatusBadge pattern in the same rows. The toggle writes -1; toggling back on restores the inherit-default state in override editors and the metric's enabled default in global defaults. In the desktop row editor the badge swallows mousedown so it doesn't blur the input, which would save and close the editor before the click lands. Also fix the off-value inconsistency found while triaging #1642: the thresholds help banner told users to type 0, which the edit-state off detection (=== -1) never recognises. Standardize the advertised disable value on -1, matching docs/FAQ.md and the engine's actual off sentinel; read-mode cells keep treating <= 0 as Off so overrides saved as 0 under the old banner still display correctly. Closes #1642. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Contract-Neutral: UI-only off toggle over existing -1 threshold semantics; no alert truth or identity change
This commit is contained in:
+1
-1
@@ -70,7 +70,7 @@ Pulse v6 organises the UI by **task** instead of **platform**:
|
||||
Legacy URLs (`/proxmox`, `/docker`, `/kubernetes`, `/hosts`, `/services`) redirect automatically. See [Migration Guide](MIGRATION_UNIFIED_NAV.md) for the full mapping.
|
||||
|
||||
### Can I disable alerts for specific metrics?
|
||||
Yes. Go to **Alerts → Thresholds** and set any value to `-1` to disable it. You can do this globally or per-resource (VM/Node).
|
||||
Yes. Go to **Alerts → Thresholds** and use the On/Off toggle next to any metric while editing, or set the value to `-1`. You can do this globally or per-resource (VM/Node).
|
||||
|
||||
### How do I monitor temperature?
|
||||
Recommended: install the unified agent on your Proxmox hosts with Proxmox integration enabled:
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
getAlertResourceTableCustomBadgeLabel,
|
||||
getAlertResourceTableEmptyState,
|
||||
getAlertResourceTableMetricInputTitle,
|
||||
getAlertResourceTableMetricOffToggleProps,
|
||||
getAlertResourceTableMetricPlaceholder,
|
||||
getAlertResourceTableOfflineStateOrder,
|
||||
getAlertResourceTableOfflineStatePresentation,
|
||||
@@ -228,46 +229,59 @@ export function AlertResourceTableDesktop(props: AlertResourceTableDesktopProps)
|
||||
<TableCell
|
||||
class={`${getPlatformTableCellClassForKind(getAlertResourceColumnKind(column))} align-middle`}
|
||||
>
|
||||
<div class="relative flex justify-center w-full">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={getAlertResourceMetricStep(metric)}
|
||||
value={isOff() ? '' : value()}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isOff())}
|
||||
disabled={isOff()}
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: Number.isNaN(nextValue) ? 0 : nextValue,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
class={`w-16 px-2 py-0.5 text-sm text-center border rounded ${
|
||||
isOff()
|
||||
? 'border-border bg-surface-alt text-muted italic placeholder: dark:placeholder: placeholder:opacity-60 pointer-events-none'
|
||||
: 'border-border text-base-content focus:border-blue-500 focus:ring-1 focus:ring-blue-500'
|
||||
}`}
|
||||
title={getAlertResourceTableMetricInputTitle(isOff())}
|
||||
/>
|
||||
<Show when={isOff()}>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 w-full rounded cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400"
|
||||
onClick={() => {
|
||||
<div class="flex items-center justify-center gap-1.5 w-full">
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={getAlertResourceMetricStep(metric)}
|
||||
value={isOff() ? '' : value()}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isOff())}
|
||||
disabled={isOff()}
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: getAlertResourceEnabledDefault(metric),
|
||||
[metric]: Number.isNaN(nextValue) ? 0 : nextValue,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
title={getAlertResourceTableMetricInputTitle(true)}
|
||||
>
|
||||
<span class="sr-only">Enable {column} default</span>
|
||||
</button>
|
||||
</Show>
|
||||
class={`w-16 px-2 py-0.5 text-sm text-center border rounded ${
|
||||
isOff()
|
||||
? 'border-border bg-surface-alt text-muted italic placeholder: dark:placeholder: placeholder:opacity-60 pointer-events-none'
|
||||
: 'border-border text-base-content focus:border-blue-500 focus:ring-1 focus:ring-blue-500'
|
||||
}`}
|
||||
title={getAlertResourceTableMetricInputTitle(isOff())}
|
||||
/>
|
||||
<Show when={isOff()}>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 w-full rounded cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400"
|
||||
onClick={() => {
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: getAlertResourceEnabledDefault(metric),
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
title={getAlertResourceTableMetricInputTitle(true)}
|
||||
>
|
||||
<span class="sr-only">Enable {column} default</span>
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
<StatusBadge
|
||||
isEnabled={!isOff()}
|
||||
onToggle={() => {
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: isOff() ? getAlertResourceEnabledDefault(metric) : -1,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
{...getAlertResourceTableMetricOffToggleProps()}
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
);
|
||||
|
||||
@@ -8,11 +8,13 @@ import { ActionIconButton } from '@/components/shared/Button';
|
||||
import { Card } from '@/components/shared/Card';
|
||||
import { FormTextarea } from '@/components/shared/FormTextarea';
|
||||
import { TogglePrimitive } from '@/components/shared/Toggle';
|
||||
import { StatusBadge } from '@/components/shared/StatusBadge';
|
||||
import { AlertResourceGroupHeader } from './AlertResourceGroupHeader';
|
||||
import {
|
||||
getAlertResourceTableCustomBadgeLabel,
|
||||
getAlertResourceTableEditNotePlaceholder,
|
||||
getAlertResourceTableEmptyState,
|
||||
getAlertResourceTableMetricOffToggleProps,
|
||||
getAlertResourceTableMetricPlaceholder,
|
||||
getAlertResourceTableRevertToDefaultsLabel,
|
||||
} from '@/utils/alertResourceTablePresentation';
|
||||
@@ -155,39 +157,52 @@ export function AlertResourceTableMobile(props: AlertResourceTableMobileProps) {
|
||||
return (
|
||||
<div class="p-2 bg-surface rounded border border-border-subtle flex flex-col gap-1">
|
||||
<span class="text-[10px] uppercase text-slate-500 font-medium">{column}</span>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={getAlertResourceMetricStep(metric)}
|
||||
value={isOff() ? '' : value()}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isOff())}
|
||||
disabled={isOff()}
|
||||
class={`w-full text-sm p-1 rounded border text-center ${isOff() ? 'bg-surface-hover' : ' border-border'}`}
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: Number.isNaN(nextValue) ? 0 : nextValue,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
/>
|
||||
<Show when={isOff()}>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 w-full"
|
||||
onClick={() => {
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="relative flex-1">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={getAlertResourceMetricStep(metric)}
|
||||
value={isOff() ? '' : value()}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isOff())}
|
||||
disabled={isOff()}
|
||||
class={`w-full text-sm p-1 rounded border text-center ${isOff() ? 'bg-surface-hover' : ' border-border'}`}
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: getAlertResourceEnabledDefault(metric),
|
||||
[metric]: Number.isNaN(nextValue) ? 0 : nextValue,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
aria-label={`Enable ${column} default`}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={isOff()}>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute inset-0 w-full"
|
||||
onClick={() => {
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: getAlertResourceEnabledDefault(metric),
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
aria-label={`Enable ${column} default`}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
<StatusBadge
|
||||
isEnabled={!isOff()}
|
||||
onToggle={() => {
|
||||
props.table.setGlobalDefaults?.((prev) => ({
|
||||
...prev,
|
||||
[metric]: isOff() ? getAlertResourceEnabledDefault(metric) : -1,
|
||||
}));
|
||||
props.table.setHasUnsavedChanges?.(true);
|
||||
}}
|
||||
{...getAlertResourceTableMetricOffToggleProps()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -350,21 +365,35 @@ export function AlertResourceTableMobile(props: AlertResourceTableMobileProps) {
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
value={thresholds()?.[metric] ?? ''}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isDisabled())}
|
||||
class="w-16 text-right text-xs p-1 rounded border border-border bg-surface"
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setEditingThresholds({
|
||||
...props.table.editingThresholds(),
|
||||
[metric]: Number.isNaN(nextValue) ? undefined : nextValue,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
value={isDisabled() ? '' : (thresholds()?.[metric] ?? '')}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(
|
||||
isDisabled(),
|
||||
)}
|
||||
class="w-16 text-right text-xs p-1 rounded border border-border bg-surface"
|
||||
onInput={(e) => {
|
||||
const nextValue = parseFloat(e.currentTarget.value);
|
||||
props.table.setEditingThresholds({
|
||||
...props.table.editingThresholds(),
|
||||
[metric]: Number.isNaN(nextValue) ? undefined : nextValue,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<StatusBadge
|
||||
isEnabled={!isDisabled()}
|
||||
onToggle={() =>
|
||||
props.table.setEditingThresholds({
|
||||
...props.table.editingThresholds(),
|
||||
[metric]: isDisabled() ? undefined : -1,
|
||||
})
|
||||
}
|
||||
{...getAlertResourceTableMetricOffToggleProps()}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
getAlertResourceTableCustomBadgeLabel,
|
||||
getAlertResourceTableEditMetricTitle,
|
||||
getAlertResourceTableMetricInputTitle,
|
||||
getAlertResourceTableMetricOffToggleProps,
|
||||
getAlertResourceTableMetricPlaceholder,
|
||||
getAlertResourceTableOfflineStateOrder,
|
||||
getAlertResourceTableOfflineStatePresentation,
|
||||
@@ -438,13 +439,13 @@ export function AlertResourceTableRow(props: AlertResourceTableRowProps) {
|
||||
);
|
||||
})()}
|
||||
</Show>
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="flex items-center justify-center gap-1.5">
|
||||
<input
|
||||
type="number"
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={getAlertResourceMetricStep(metric)}
|
||||
value={getThresholds()?.[metric] ?? ''}
|
||||
value={isDisabled() ? '' : (getThresholds()?.[metric] ?? '')}
|
||||
placeholder={getAlertResourceTableMetricPlaceholder(isDisabled())}
|
||||
title={getAlertResourceTableMetricInputTitle(isDisabled())}
|
||||
ref={(el) => {
|
||||
@@ -481,6 +482,17 @@ export function AlertResourceTableRow(props: AlertResourceTableRowProps) {
|
||||
: ' text-base-content border-border'
|
||||
}`}
|
||||
/>
|
||||
{/* mousedown would blur the input, which saves and closes
|
||||
the editor before this toggle's click can land */}
|
||||
<div onMouseDown={(event) => event.preventDefault()}>
|
||||
<StatusBadge
|
||||
isEnabled={!isDisabled()}
|
||||
onToggle={() =>
|
||||
updateEditingThreshold(metric, isDisabled() ? undefined : -1)
|
||||
}
|
||||
{...getAlertResourceTableMetricOffToggleProps()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { Show, For, createSignal, createEffect } from 'solid-js';
|
||||
import { Dialog } from '../shared/Dialog';
|
||||
import { StatusBadge } from '../shared/StatusBadge';
|
||||
import { ThresholdSlider } from '../Workloads/ThresholdSlider';
|
||||
import {
|
||||
getAlertResourceTableMetricOffToggleProps,
|
||||
getAlertResourceTableMetricPlaceholder,
|
||||
} from '@/utils/alertResourceTablePresentation';
|
||||
import {
|
||||
ALERT_BULK_EDIT_CANCEL_LABEL,
|
||||
ALERT_BULK_EDIT_CLEAR_LABEL,
|
||||
@@ -102,14 +107,31 @@ export function BulkEditDialog(props: BulkEditDialogProps) {
|
||||
if (metric === 'backup' || metric === 'snapshot') return null;
|
||||
const bounds = getMetricBounds(metric);
|
||||
const val = () => thresholds()[metric];
|
||||
const isOff = () => val() === -1;
|
||||
|
||||
return (
|
||||
<div class="space-y-2 pb-4 border-b border-border-subtle last:border-0">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<label class="text-sm font-medium text-base-content">{column}</label>
|
||||
<span class="text-xs text-slate-500 font-mono">
|
||||
{val() !== undefined ? val() : ALERT_BULK_EDIT_UNCHANGED_LABEL}
|
||||
</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500 font-mono">
|
||||
{isOff()
|
||||
? getAlertResourceTableMetricPlaceholder(true)
|
||||
: val() !== undefined
|
||||
? val()
|
||||
: ALERT_BULK_EDIT_UNCHANGED_LABEL}
|
||||
</span>
|
||||
<StatusBadge
|
||||
isEnabled={!isOff()}
|
||||
onToggle={() =>
|
||||
setThresholds((prev) => ({
|
||||
...prev,
|
||||
[metric]: isOff() ? undefined : -1,
|
||||
}))
|
||||
}
|
||||
{...getAlertResourceTableMetricOffToggleProps()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex-1">
|
||||
@@ -119,7 +141,7 @@ export function BulkEditDialog(props: BulkEditDialogProps) {
|
||||
type={metric as 'cpu' | 'memory' | 'disk' | 'temperature'}
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
value={val() !== undefined ? val()! : bounds.min}
|
||||
value={val() !== undefined && !isOff() ? val()! : bounds.min}
|
||||
onChange={(v) => {
|
||||
setThresholds((prev) => ({ ...prev, [metric]: v }));
|
||||
}}
|
||||
@@ -132,8 +154,12 @@ export function BulkEditDialog(props: BulkEditDialogProps) {
|
||||
min={bounds.min}
|
||||
max={bounds.max}
|
||||
step={bounds.step}
|
||||
value={val() ?? ''}
|
||||
placeholder={ALERT_BULK_EDIT_UNCHANGED_LABEL}
|
||||
value={isOff() ? '' : (val() ?? '')}
|
||||
placeholder={
|
||||
isOff()
|
||||
? getAlertResourceTableMetricPlaceholder(true)
|
||||
: ALERT_BULK_EDIT_UNCHANGED_LABEL
|
||||
}
|
||||
onInput={(e) => {
|
||||
const v = parseFloat(e.currentTarget.value);
|
||||
setThresholds((prev) => ({
|
||||
|
||||
@@ -1309,7 +1309,7 @@ describe('ResourceTable', () => {
|
||||
|
||||
// Find the editing input with the "Set to -1" title (unique to resource editing inputs)
|
||||
const editInputs = document.querySelectorAll(
|
||||
'input[type="number"][title="Set to -1 to disable alerts for this metric"]',
|
||||
'input[type="number"][title="Set to -1 or use the Off toggle to disable alerts for this metric"]',
|
||||
);
|
||||
expect(editInputs.length).toBeGreaterThanOrEqual(1);
|
||||
fireEvent.input(editInputs[0], { target: { value: '95' } });
|
||||
@@ -1332,7 +1332,7 @@ describe('ResourceTable', () => {
|
||||
render(() => <ResourceTable {...props} />);
|
||||
|
||||
const editInputs = document.querySelectorAll(
|
||||
'input[type="number"][title="Set to -1 to disable alerts for this metric"]',
|
||||
'input[type="number"][title="Set to -1 or use the Off toggle to disable alerts for this metric"]',
|
||||
);
|
||||
expect(editInputs.length).toBeGreaterThanOrEqual(1);
|
||||
fireEvent.blur(editInputs[0]);
|
||||
|
||||
@@ -230,6 +230,49 @@ describe('BulkEditDialog', () => {
|
||||
expect(saved.restartCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it('off toggle stages -1 for the metric and shows the Off state', () => {
|
||||
const props = defaultProps();
|
||||
props.columns = ['Restart Count'];
|
||||
render(() => <BulkEditDialog {...props} />);
|
||||
|
||||
const toggle = screen.getByRole('button', { name: 'On' });
|
||||
fireEvent.click(toggle);
|
||||
|
||||
// Badge flips to Off and the staged value reads Off, not -1
|
||||
expect(screen.getByRole('button', { name: 'Off' })).toBeInTheDocument();
|
||||
expect(screen.getByText('Off', { selector: 'span' })).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByText(/Apply to 3 items/));
|
||||
expect(props.onSave).toHaveBeenCalledWith({ restartCount: -1 });
|
||||
});
|
||||
|
||||
it('off toggle returns the metric to Unchanged when clicked again', () => {
|
||||
const props = defaultProps();
|
||||
props.columns = ['Restart Count'];
|
||||
render(() => <BulkEditDialog {...props} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'On' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Off' }));
|
||||
|
||||
expect(screen.getByText('Unchanged')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText(/Apply to 3 items/));
|
||||
const saved = props.onSave.mock.calls[0][0] as Record<string, number | undefined>;
|
||||
expect(saved.restartCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it('typing a value after turning a metric off replaces the staged -1', () => {
|
||||
const props = defaultProps();
|
||||
props.columns = ['Restart Count'];
|
||||
render(() => <BulkEditDialog {...props} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'On' }));
|
||||
const input = screen.getByRole('spinbutton');
|
||||
fireEvent.input(input, { target: { value: '7' } });
|
||||
|
||||
fireEvent.click(screen.getByText(/Apply to 3 items/));
|
||||
expect(props.onSave).toHaveBeenCalledWith({ restartCount: 7 });
|
||||
});
|
||||
|
||||
it('displays Unchanged when threshold is not set, value when it is', () => {
|
||||
const props = defaultProps();
|
||||
props.columns = ['Restart Count'];
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ describe('alertResourceTablePresentation.branchcov0718', () => {
|
||||
it('exposes the enable/disable metric-input title constants', () => {
|
||||
expect(ALERT_RESOURCE_TABLE_ENABLE_METRIC_TITLE).toBe('Click to enable this metric');
|
||||
expect(ALERT_RESOURCE_TABLE_DISABLE_METRIC_TITLE).toBe(
|
||||
'Set to -1 to disable alerts for this metric',
|
||||
'Set to -1 or use the Off toggle to disable alerts for this metric',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
getAlertResourceTableEditNotePlaceholder,
|
||||
getAlertResourceTableEmptyState,
|
||||
getAlertResourceTableMetricInputTitle,
|
||||
getAlertResourceTableMetricOffToggleProps,
|
||||
getAlertResourceTableMetricPlaceholder,
|
||||
getAlertResourceTableNoResultsState,
|
||||
getAlertResourceTableOfflineStateOrder,
|
||||
@@ -95,8 +96,17 @@ describe('alertResourceTablePresentation', () => {
|
||||
});
|
||||
expect(getAlertResourceTableMetricInputTitle(true)).toBe('Click to enable this metric');
|
||||
expect(getAlertResourceTableMetricInputTitle(false)).toBe(
|
||||
'Set to -1 to disable alerts for this metric',
|
||||
'Set to -1 or use the Off toggle to disable alerts for this metric',
|
||||
);
|
||||
expect(getAlertResourceTableEditMetricTitle()).toBe('Click to edit this metric');
|
||||
});
|
||||
|
||||
it('exports the per-metric off-toggle badge props', () => {
|
||||
expect(getAlertResourceTableMetricOffToggleProps()).toEqual({
|
||||
labelEnabled: 'On',
|
||||
labelDisabled: 'Off',
|
||||
titleEnabled: 'Alerts enabled for this metric. Click to turn off.',
|
||||
titleDisabled: 'Alerts turned off for this metric. Click to re-enable.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -95,7 +95,10 @@ describe('alertThresholdsPresentation', () => {
|
||||
expect(getAlertThresholdsHelpDismissLabel()).toBe('Dismiss tips');
|
||||
expect(getAlertThresholdsHelpBanner()).toEqual({
|
||||
title: 'Quick tips:',
|
||||
disableValue: '0',
|
||||
// Must match the value the backend and docs/FAQ.md treat as "off";
|
||||
// the banner told users to type 0, which edit-state off detection
|
||||
// (=== -1) never recognised.
|
||||
disableValue: '-1',
|
||||
reenableLabel: 'Off',
|
||||
customBadgeLabel: 'Custom',
|
||||
collapseHint: 'Click sections to collapse/expand.',
|
||||
|
||||
@@ -4123,7 +4123,9 @@ describe('frontend resource type boundaries', () => {
|
||||
expect(alertResourceTableSource).not.toContain('Reset to factory defaults');
|
||||
expect(alertResourceTableSource).not.toContain('Alert Delay (s)');
|
||||
expect(alertResourceTableSource).not.toContain('Click to edit this metric');
|
||||
expect(alertResourceTableSource).not.toContain('Set to -1 to disable alerts for this metric');
|
||||
expect(alertResourceTableSource).not.toContain(
|
||||
'Set to -1 or use the Off toggle to disable alerts for this metric',
|
||||
);
|
||||
expect(alertResourceTableSource).not.toContain(
|
||||
"if (resource.type === 'agent' && ['diskRead', 'diskWrite', 'networkIn', 'networkOut'].includes(",
|
||||
);
|
||||
|
||||
@@ -18,8 +18,14 @@ export const ALERT_RESOURCE_TABLE_OFFLINE_STATE_CRITICAL_TITLE =
|
||||
'Offline alerts will raise critical-level notifications.';
|
||||
export const ALERT_RESOURCE_TABLE_ENABLE_METRIC_TITLE = 'Click to enable this metric';
|
||||
export const ALERT_RESOURCE_TABLE_DISABLE_METRIC_TITLE =
|
||||
'Set to -1 to disable alerts for this metric';
|
||||
'Set to -1 or use the Off toggle to disable alerts for this metric';
|
||||
export const ALERT_RESOURCE_TABLE_EDIT_METRIC_TITLE = 'Click to edit this metric';
|
||||
export const ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_LABEL_ON = 'On';
|
||||
export const ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_LABEL_OFF = 'Off';
|
||||
export const ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_TITLE_ON =
|
||||
'Alerts enabled for this metric. Click to turn off.';
|
||||
export const ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_TITLE_OFF =
|
||||
'Alerts turned off for this metric. Click to re-enable.';
|
||||
|
||||
export function getAlertResourceTableEmptyState(emptyMessage?: string) {
|
||||
return emptyMessage || ALERT_RESOURCE_TABLE_EMPTY_STATE;
|
||||
@@ -100,3 +106,12 @@ export function getAlertResourceTableMetricInputTitle(isDisabled: boolean) {
|
||||
export function getAlertResourceTableEditMetricTitle() {
|
||||
return ALERT_RESOURCE_TABLE_EDIT_METRIC_TITLE;
|
||||
}
|
||||
|
||||
export function getAlertResourceTableMetricOffToggleProps() {
|
||||
return {
|
||||
labelEnabled: ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_LABEL_ON,
|
||||
labelDisabled: ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_LABEL_OFF,
|
||||
titleEnabled: ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_TITLE_ON,
|
||||
titleDisabled: ALERT_RESOURCE_TABLE_METRIC_OFF_TOGGLE_TITLE_OFF,
|
||||
} as const;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ export function getAlertThresholdsHelpDismissLabel() {
|
||||
export function getAlertThresholdsHelpBanner() {
|
||||
return {
|
||||
title: 'Quick tips:',
|
||||
disableValue: '0',
|
||||
disableValue: '-1',
|
||||
reenableLabel: 'Off',
|
||||
customBadgeLabel: 'Custom',
|
||||
collapseHint: 'Click sections to collapse/expand.',
|
||||
|
||||
Reference in New Issue
Block a user