Skip to content

Commit 472db59

Browse files
committed
feat: replace window.confirm() with ConfirmDialog component
1 parent 63e1a37 commit 472db59

5 files changed

Lines changed: 230 additions & 141 deletions

File tree

imagelab-backend/app/utils/color.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import re
22

3-
43
HEX_COLOR_RE = re.compile(r"^[0-9a-fA-F]{6}$")
54

65

@@ -19,17 +18,13 @@ def hex_to_bgr(hex_color: str) -> tuple[int, int, int]:
1918
ValueError: If hex_color is not a valid 6-digit hex color string.
2019
"""
2120
if not isinstance(hex_color, str):
22-
raise TypeError(
23-
f"hex_to_bgr expects a str, got {type(hex_color).__name__!r}"
24-
)
21+
raise TypeError(f"hex_to_bgr expects a str, got {type(hex_color).__name__!r}")
2522

2623
original = hex_color
2724
normalized = hex_color.removeprefix("#")
2825

2926
if not HEX_COLOR_RE.fullmatch(normalized):
30-
raise ValueError(
31-
f"Invalid hex color: {original!r}. Expected format '#rrggbb' or 'rrggbb'."
32-
)
27+
raise ValueError(f"Invalid hex color: {original!r}. Expected format '#rrggbb' or 'rrggbb'.")
3328

3429
r = int(normalized[0:2], 16)
3530
g = int(normalized[2:4], 16)

imagelab-backend/tests/test_filtering_operators.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ def test_asymmetric_kernel_uses_width_height_convention(self):
8080
image = np.arange(75, dtype=np.uint8).reshape(5, 5, 3)
8181
width, height = 1, 5
8282

83-
result = BoxFilter({"width": width, "height": height, "depth": -1}).compute(
84-
image
85-
)
83+
result = BoxFilter({"width": width, "height": height, "depth": -1}).compute(image)
8684
expected = cv2.boxFilter(
8785
image,
8886
-1,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { useEffect } from "react";
2+
3+
interface ConfirmDialogProps {
4+
message: string;
5+
onConfirm: () => void;
6+
onCancel: () => void;
7+
}
8+
9+
export default function ConfirmDialog({ message, onConfirm, onCancel }: ConfirmDialogProps) {
10+
// Close on Escape key — mirrors SharePipelineModal pattern
11+
useEffect(() => {
12+
const handler = (e: KeyboardEvent) => {
13+
if (e.key === "Escape") onCancel();
14+
};
15+
document.addEventListener("keydown", handler);
16+
return () => document.removeEventListener("keydown", handler);
17+
}, [onCancel]);
18+
19+
return (
20+
<div
21+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
22+
onClick={onCancel}
23+
role="presentation"
24+
>
25+
<div
26+
role="alertdialog"
27+
aria-modal="true"
28+
aria-describedby="confirm-dialog-message"
29+
className="bg-white rounded-xl shadow-2xl w-full max-w-sm mx-4 overflow-hidden"
30+
onClick={(e) => e.stopPropagation()}
31+
>
32+
{/* Body */}
33+
<div className="px-5 py-5">
34+
<p id="confirm-dialog-message" className="text-sm text-gray-700 leading-relaxed">
35+
{message}
36+
</p>
37+
</div>
38+
39+
{/* Actions */}
40+
<div className="flex justify-end gap-2 px-5 pb-4">
41+
<button
42+
type="button"
43+
onClick={onCancel}
44+
className="px-4 py-1.5 rounded-lg text-sm font-medium border border-gray-200 text-gray-600 hover:bg-gray-50 transition-colors"
45+
>
46+
Cancel
47+
</button>
48+
<button
49+
type="button"
50+
onClick={onConfirm}
51+
className="px-4 py-1.5 rounded-lg text-sm font-medium text-white bg-indigo-500 hover:bg-indigo-600 transition-colors"
52+
>
53+
OK
54+
</button>
55+
</div>
56+
</div>
57+
</div>
58+
);
59+
}

0 commit comments

Comments
 (0)