fix: add validation error handling to InactiveJailDetail

- Add validationError state to show network/API failures to user
- Use handleFetchError to properly handle auth errors (suppress generic error banner, trigger session-expiry flow)
- Clear validationError when user clicks Validate again
- Ensure error MessageBar renders instead of success banner when validation fails
- Fix InactiveJailDetail onValidate to return Promise as expected by prop type
- Fix useJailConfigs test to use correct JailConfig interface

Fixes TASK-BUG-05: prevents silent validation failures where user cannot distinguish between clean 'no issues' result and server error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-23 08:02:24 +02:00
parent 3c310e1d79
commit 1d50bc1a73
2 changed files with 29 additions and 23 deletions

View File

@@ -32,6 +32,7 @@ import {
Play24Regular,
} from "@fluentui/react-icons";
import { ApiError } from "../../api/client";
import { handleFetchError } from "../../utils/fetchError";
import type {
AddLogPathRequest,
BackendType,
@@ -651,13 +652,17 @@ function InactiveJailDetail({
const styles = useConfigStyles();
const [validating, setValidating] = useState(false);
const [validationResult, setValidationResult] = useState<JailValidationResult | null>(null);
const [validationError, setValidationError] = useState<string | null>(null);
const handleValidate = useCallback((): void => {
setValidating(true);
setValidationResult(null);
setValidationError(null);
onValidate()
.then((result) => { setValidationResult(result); })
.catch(() => { /* validation call failed — ignore */ })
.catch((err: unknown) => {
handleFetchError(err, setValidationError, "Validation request failed.");
})
.finally(() => { setValidating(false); });
}, [onValidate]);
@@ -700,8 +705,17 @@ function InactiveJailDetail({
<Input readOnly value={jail.source_file} className={styles.codeFont} />
</Field>
{/* Validation error panel */}
{validationError !== null && (
<div style={{ marginBottom: tokens.spacingVerticalM }}>
<MessageBar intent="error">
<MessageBarBody>{validationError}</MessageBarBody>
</MessageBar>
</div>
)}
{/* Validation result panel */}
{validationResult !== null && (
{validationResult !== null && validationError === null && (
<div style={{ marginBottom: tokens.spacingVerticalM }}>
{blockingIssues.length === 0 && advisoryIssues.length === 0 ? (
<MessageBar intent="success">
@@ -924,7 +938,7 @@ export function JailsTab({ initialJail }: JailsTabProps): React.JSX.Element {
? (): void => { void handleDeactivateInactive(selectedInactiveJail.name); }
: undefined
}
onValidate={() => { void validateJailConfig(selectedInactiveJail.name); }}
onValidate={async () => validateJailConfig(selectedInactiveJail.name)}
/>
) : null}
</ConfigListDetail>