Improve resource usage meter states and accessibility
This commit is contained in:
@@ -2,7 +2,7 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import operationControlsSource from "./OperationControls.tsx?raw";
|
||||
import { ConfirmDialog, ManagementDialog } from "./OperationControls";
|
||||
import { ConfirmDialog, ManagementDialog, UsageMeter } from "./OperationControls";
|
||||
|
||||
describe("shared operation dialogs", () => {
|
||||
it("renders labelled, busy-aware confirmation semantics", () => {
|
||||
@@ -42,4 +42,27 @@ describe("shared operation dialogs", () => {
|
||||
expect(html).toContain("编辑资源");
|
||||
expect(html).toContain('aria-modal="true"');
|
||||
});
|
||||
|
||||
it("renders resource meters with meaningful known, pending, and missing states", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<>
|
||||
<UsageMeter label="磁盘" percent={78} />
|
||||
<UsageMeter label="CPU" pending />
|
||||
<UsageMeter label="内存" />
|
||||
</>
|
||||
);
|
||||
|
||||
expect(html).toContain("磁盘");
|
||||
expect(html).toContain("78%");
|
||||
expect(html).toContain("偏高");
|
||||
expect(html).toContain('role="meter"');
|
||||
expect(html).toContain('aria-valuenow="78"');
|
||||
expect(html).toContain("CPU");
|
||||
expect(html).toContain("读取中");
|
||||
expect(html).toContain("等待指标");
|
||||
expect(html).toContain("内存");
|
||||
expect(html).toContain("未上报");
|
||||
expect(html).toContain("等待 Run");
|
||||
expect(html).not.toContain("--");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -140,18 +140,23 @@ function useDialogLifecycle(open: boolean, onClose: () => void, canClose: boolea
|
||||
interface UsageMeterProps {
|
||||
label: string;
|
||||
percent?: number;
|
||||
pending?: boolean;
|
||||
}
|
||||
|
||||
export function UsageMeter({ label, percent }: UsageMeterProps) {
|
||||
export function UsageMeter({ label, percent, pending = false }: UsageMeterProps) {
|
||||
const known = typeof percent === "number" && Number.isFinite(percent);
|
||||
const clamped = known ? Math.max(0, Math.min(100, percent)) : 0;
|
||||
const rounded = Math.round(clamped);
|
||||
const state = known ? (clamped >= 85 ? "critical" : clamped >= 70 ? "watch" : "normal") : pending ? "pending" : "missing";
|
||||
const stateLabel = known ? (clamped >= 85 ? "警戒" : clamped >= 70 ? "偏高" : "正常") : pending ? "读取中" : "未上报";
|
||||
const trackText = pending ? "等待指标" : "等待 Run";
|
||||
return (
|
||||
<div className="usage-meter">
|
||||
<span>{label}</span>
|
||||
<span className="usage-meter-track" role="img" aria-label={known ? `${label} ${Math.round(clamped)}%` : `${label} 暂无数据`}>
|
||||
{known && <span className={`usage-meter-fill${clamped >= 85 ? " usage-high" : ""}`} style={{ width: `${clamped}%` }} />}
|
||||
<div className={`usage-meter usage-meter-${state}`} title={known ? `${label} ${rounded}% ${stateLabel}` : `${label} ${stateLabel}`}>
|
||||
<span className="usage-meter-label"><span>{label}</span><small>{stateLabel}</small></span>
|
||||
<span className="usage-meter-value">{known ? `${rounded}%` : stateLabel}</span>
|
||||
<span className="usage-meter-track" role={known ? "meter" : "img"} aria-label={known ? `${label} ${rounded}% ${stateLabel}` : `${label} ${stateLabel}`} aria-valuemin={known ? 0 : undefined} aria-valuemax={known ? 100 : undefined} aria-valuenow={known ? rounded : undefined} aria-valuetext={known ? undefined : stateLabel}>
|
||||
{known ? <span className="usage-meter-fill" style={{ width: `${clamped}%` }} /> : <span className="usage-meter-placeholder">{trackText}</span>}
|
||||
</span>
|
||||
<span className="usage-meter-value">{known ? `${Math.round(clamped)}%` : "--"}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user