From 31a9bcebf575e0182b4d146ea1f2ece72f273af8 Mon Sep 17 00:00:00 2001
From: "pulse-triage[bot]"
<249995291+pulse-triage[bot]@users.noreply.github.com>
Date: Sun, 30 Aug 2026 20:11:39 +0100
Subject: [PATCH] Harden discovery assurance feedback
---
frontend-modern/browser-verification.json | 32 ++-
.../Discovery/AvailabilityProposalCard.tsx | 227 +++++++++++-------
.../AvailabilityProposalCard.test.tsx | 180 +++++++++++++-
3 files changed, 341 insertions(+), 98 deletions(-)
diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json
index 895f15791e..afead0ca67 100644
--- a/frontend-modern/browser-verification.json
+++ b/frontend-modern/browser-verification.json
@@ -1,13 +1,17 @@
{
"version": 1,
- "base_sha": "defc24af837b91428fbee939d09cd31e9559fb4f",
- "verified_at": "2026-08-30T18:33:03Z",
+ "base_sha": "b0de28c7c406468310dfbef95b00bd71400d8abb",
+ "verified_at": "2026-08-30T19:10:01Z",
"result": "passed",
- "changed_paths": ["frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx"],
+ "changed_paths": [
+ "frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx"
+ ],
"content_sha256": {
- "frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx": "8432b423e90ebb0e8dbc56ae82535b992bb7715be688cf6f95be34c1d12564e4"
+ "frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx": "0e3c4c5c2bb63ac5c8cd2549cb1fccea3b17d86a8bffa4dd7d0bf0aca7f45000"
},
- "routes": ["/docker/overview?q=uptime-kuma"],
+ "routes": [
+ "/browser-assurance-harness.html (temporary current-build Vite harness for the /docker/overview discovery proposal card)"
+ ],
"viewports": [
{
"width": 1280,
@@ -19,14 +23,18 @@
}
],
"states": [
- "current-build AvailabilityProposalCard with a discovered Uptime Kuma verification proposal",
- "inline proposal evidence and canonical attachment copy",
- "open machine assurance suggestions dialog with one reviewable HTTP service",
- "desktop and phone-width proposal card and dialog layouts"
+ "existing-check inventory loading, failure, retry recovery, empty inventory, and post-create duplicate detection",
+ "proposal test transport success, application failure, and request failure with scoped status or alert feedback",
+ "created active-check confirmation alongside duplicate protection",
+ "machine-review loading, populated, and load-failure states without false empty-state overlap",
+ "settled desktop and narrow card/dialog pixels from the final current-source Vite render; managed full-app startup was blocked by unrelated pulse-pro go.mod drift"
],
"interactions": [
- "opened Review machine suggestions and verified the evidence-specific dismissal copy",
- "closed the machine suggestions dialog with Escape",
- "verified card and dialog bounds, wrapping, scrolling, and absence of horizontal overflow at desktop and phone widths"
+ "confirmed Create active check stays disabled until existing-check inventory succeeds and retry restores it",
+ "ran successful and failed Test proposal actions and confirmed focus returns after the native loading-button blur",
+ "created an active check and confirmed status plus duplicate feedback",
+ "opened machine review, checked loading and populated states, closed with Escape, and confirmed focus return",
+ "reopened machine review on failure and confirmed proposal errors stay outside the dialog and no false empty state appears",
+ "inspected desktop and 390x844 settled pixels, topmost dialog hit testing, bounds, clipping, scrolling, and horizontal overflow"
]
}
diff --git a/frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx b/frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx
index dd3d45b152..d05916192d 100644
--- a/frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx
+++ b/frontend-modern/src/components/Discovery/AvailabilityProposalCard.tsx
@@ -77,7 +77,8 @@ export const AvailabilityProposalCard: Component
const [saving, setSaving] = createSignal(false);
const [testing, setTesting] = createSignal(false);
const [updatingDisposition, setUpdatingDisposition] = createSignal(false);
- const [error, setError] = createSignal(null);
+ const [proposalError, setProposalError] = createSignal(null);
+ const [bulkReviewError, setBulkReviewError] = createSignal(null);
const [testResult, setTestResult] = createSignal(null);
const [createdTarget, setCreatedTarget] = createSignal(null);
const [showBulkReview, setShowBulkReview] = createSignal(false);
@@ -97,18 +98,20 @@ export const AvailabilityProposalCard: Component
setName(current.service_name || props.discovery.service_name || props.discovery.hostname);
setTestResult(null);
setCreatedTarget(null);
- setError(null);
+ setProposalError(null);
+ setBulkReviewError(null);
});
const duplicate = createMemo(() => {
const current = proposal();
- if (!current) return null;
+ if (!current || targets.error) return null;
return findAvailabilityProposalDuplicate(current, props.canonicalResourceId, targets() ?? []);
});
const dismissed = createMemo(() => isAvailabilityProposalDismissed(props.discovery));
- const bulkItems = createMemo(() =>
- reviewableAvailabilitySummaries(machineDiscoveries()?.discoveries ?? []),
- );
+ const bulkItems = createMemo(() => {
+ if (machineDiscoveries.error) return [];
+ return reviewableAvailabilitySummaries(machineDiscoveries()?.discoveries ?? []);
+ });
const buildTarget = (): AvailabilityTarget | null => {
const current = proposal();
@@ -122,32 +125,33 @@ export const AvailabilityProposalCard: Component
});
};
- const handleTest = async () => {
+ const handleTest = async (trigger?: HTMLButtonElement) => {
const target = buildTarget();
if (!target) return;
setTesting(true);
- setError(null);
+ setProposalError(null);
setTestResult(null);
try {
setTestResult(await AvailabilityTargetsAPI.test(target));
} catch (cause) {
- setError(cause instanceof Error ? cause.message : 'Failed to test this proposal.');
+ setProposalError(cause instanceof Error ? cause.message : 'Failed to test this proposal.');
} finally {
setTesting(false);
+ queueMicrotask(() => trigger?.focus());
}
};
const handleCreate = async () => {
const target = buildTarget();
- if (!target || duplicate()?.kind === 'endpoint') return;
+ if (!target || targets.loading || targets.error || duplicate()?.kind === 'endpoint') return;
setSaving(true);
- setError(null);
+ setProposalError(null);
try {
const created = await AvailabilityTargetsAPI.create(target);
setCreatedTarget(created);
await refetchTargets();
} catch (cause) {
- setError(cause instanceof Error ? cause.message : 'Failed to create this check.');
+ setProposalError(cause instanceof Error ? cause.message : 'Failed to create this check.');
} finally {
setSaving(false);
}
@@ -158,11 +162,11 @@ export const AvailabilityProposalCard: Component
if (!current) return;
const fingerprint = current.evidence_fingerprint?.trim();
if (!fingerprint) {
- setError('Run discovery again before changing this legacy suggestion.');
+ setProposalError('Run discovery again before changing this legacy suggestion.');
return;
}
setUpdatingDisposition(true);
- setError(null);
+ setProposalError(null);
try {
const updated = await updateAvailabilityProposal(
props.resourceType,
@@ -174,7 +178,7 @@ export const AvailabilityProposalCard: Component
props.onDiscoveryUpdated(updated);
if (showBulkReview()) await refetchMachineDiscoveries();
} catch (cause) {
- setError(
+ setProposalError(
cause instanceof Error ? cause.message : 'Failed to update this proposal review state.',
);
} finally {
@@ -190,11 +194,11 @@ export const AvailabilityProposalCard: Component
if (!current) return;
const fingerprint = current.evidence_fingerprint?.trim();
if (!fingerprint) {
- setError('Run discovery again before changing this legacy suggestion.');
+ setBulkReviewError('Run discovery again before changing this legacy suggestion.');
return;
}
setUpdatingDisposition(true);
- setError(null);
+ setBulkReviewError(null);
try {
const updated = await updateAvailabilityProposal(
summary.resource_type,
@@ -206,7 +210,9 @@ export const AvailabilityProposalCard: Component
if (summary.id === props.discovery.id) props.onDiscoveryUpdated(updated);
await refetchMachineDiscoveries();
} catch (cause) {
- setError(cause instanceof Error ? cause.message : 'Failed to update the selected proposal.');
+ setBulkReviewError(
+ cause instanceof Error ? cause.message : 'Failed to update the selected proposal.',
+ );
} finally {
setUpdatingDisposition(false);
}
@@ -234,7 +240,14 @@ export const AvailabilityProposalCard: Component
Nothing is created until you choose the active-check action below.
-