fix: handle invalid date formats gracefully and add missing dialog descriptions
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 4m14s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 4m14s
- Wrap date.fromisoformat() in try/except in case_update tool — prevents unhandled ValueError from surfacing as 500; FastAPI now catches it as 422 - Add DialogDescription (sr-only) to 5 dialogs missing aria-describedby: documents-panel preview + delete, drafts-panel delete + feedback, link-related-dialog Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -326,9 +326,15 @@ async def case_update(
|
|||||||
if notes:
|
if notes:
|
||||||
fields["notes"] = notes
|
fields["notes"] = notes
|
||||||
if hearing_date:
|
if hearing_date:
|
||||||
fields["hearing_date"] = date_type.fromisoformat(hearing_date)
|
try:
|
||||||
|
fields["hearing_date"] = date_type.fromisoformat(hearing_date)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ValueError(f"Invalid hearing_date format: {hearing_date!r}") from exc
|
||||||
if decision_date:
|
if decision_date:
|
||||||
fields["decision_date"] = date_type.fromisoformat(decision_date)
|
try:
|
||||||
|
fields["decision_date"] = date_type.fromisoformat(decision_date)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ValueError(f"Invalid decision_date format: {decision_date!r}") from exc
|
||||||
if tags is not None:
|
if tags is not None:
|
||||||
fields["tags"] = tags
|
fields["tags"] = tags
|
||||||
if expected_outcome:
|
if expected_outcome:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Progress } from "@/components/ui/progress";
|
|||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
@@ -127,6 +128,7 @@ function DocumentPreviewDialog({
|
|||||||
<DialogContent className="sm:max-w-2xl max-h-[80vh] flex flex-col" dir="rtl">
|
<DialogContent className="sm:max-w-2xl max-h-[80vh] flex flex-col" dir="rtl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-right">{displayName}</DialogTitle>
|
<DialogTitle className="text-right">{displayName}</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">תצוגה מקדימה של תוכן המסמך</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
{loading && (
|
{loading && (
|
||||||
@@ -184,6 +186,7 @@ function DeleteConfirmDialog({
|
|||||||
<DialogContent dir="rtl">
|
<DialogContent dir="rtl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-right">מחיקת מסמך</DialogTitle>
|
<DialogTitle className="text-right">מחיקת מסמך</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">אישור מחיקת המסמך מהתיק</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<p className="text-sm text-ink-muted text-right">
|
<p className="text-sm text-ink-muted text-right">
|
||||||
האם למחוק את המסמך <strong>“{displayName}”</strong>?
|
האם למחוק את המסמך <strong>“{displayName}”</strong>?
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Textarea } from "@/components/ui/textarea";
|
|||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
@@ -323,6 +324,7 @@ export function DraftsPanel({
|
|||||||
<DialogContent className="sm:max-w-sm" dir="rtl">
|
<DialogContent className="sm:max-w-sm" dir="rtl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>מחיקת טיוטה</DialogTitle>
|
<DialogTitle>מחיקת טיוטה</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">אישור מחיקת קובץ הטיוטה</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<p className="text-sm text-ink-muted">
|
<p className="text-sm text-ink-muted">
|
||||||
למחוק את הקובץ{" "}
|
למחוק את הקובץ{" "}
|
||||||
@@ -493,6 +495,7 @@ function NewCaseFeedbackDialog({ caseNumber }: { caseNumber: string }) {
|
|||||||
<DialogContent className="sm:max-w-lg" dir="rtl">
|
<DialogContent className="sm:max-w-lg" dir="rtl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>הערת יו״ר — תיק {caseNumber}</DialogTitle>
|
<DialogTitle>הערת יו״ר — תיק {caseNumber}</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">הוספת הערת יו״ר על בלוק בהחלטה</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<form onSubmit={handleSubmit} className="space-y-4 mt-2">
|
<form onSubmit={handleSubmit} className="space-y-4 mt-2">
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { toast } from "sonner";
|
|||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
@@ -68,6 +69,7 @@ function LinkDialog({ caseId, currentRelated, open, onOpenChange }: DialogProps)
|
|||||||
<DialogContent className="max-w-lg" dir="rtl">
|
<DialogContent className="max-w-lg" dir="rtl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="text-navy">קשר החלטה קשורה</DialogTitle>
|
<DialogTitle className="text-navy">קשר החלטה קשורה</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">חיפוש וקישור תקדים או החלטה קשורה לתיק</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
|
|||||||
33
web/app.py
33
web/app.py
@@ -1378,21 +1378,24 @@ async def api_case_update(case_number: str, req: CaseUpdateRequest, background_t
|
|||||||
existing = await db.get_case_by_number(case_number)
|
existing = await db.get_case_by_number(case_number)
|
||||||
old_status = (existing or {}).get("status", "")
|
old_status = (existing or {}).get("status", "")
|
||||||
|
|
||||||
result = await cases_tools.case_update(
|
try:
|
||||||
case_number=case_number,
|
result = await cases_tools.case_update(
|
||||||
status=req.status,
|
case_number=case_number,
|
||||||
title=req.title,
|
status=req.status,
|
||||||
subject=req.subject,
|
title=req.title,
|
||||||
notes=req.notes,
|
subject=req.subject,
|
||||||
hearing_date=req.hearing_date,
|
notes=req.notes,
|
||||||
decision_date=req.decision_date,
|
hearing_date=req.hearing_date,
|
||||||
tags=req.tags,
|
decision_date=req.decision_date,
|
||||||
expected_outcome=req.expected_outcome,
|
tags=req.tags,
|
||||||
appellants=req.appellants,
|
expected_outcome=req.expected_outcome,
|
||||||
respondents=req.respondents,
|
appellants=req.appellants,
|
||||||
property_address=req.property_address,
|
respondents=req.respondents,
|
||||||
permit_number=req.permit_number,
|
property_address=req.property_address,
|
||||||
)
|
permit_number=req.permit_number,
|
||||||
|
)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise HTTPException(422, str(exc))
|
||||||
try:
|
try:
|
||||||
parsed = json.loads(result)
|
parsed = json.loads(result)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
|
|||||||
Reference in New Issue
Block a user