fix: Phase 2 QA — all 25 remaining HIGH/MEDIUM/LOW issues
HIGH fixes (7): - H1: VNCdirectory admin i18n — 30+ translation keys added - H2: handleSave try/catch with error toast - H3: Free/busy accountId scoping - H4: cancelEventBookings filter by eventId - H5: Resource picker static apiFetch import - H6: Sharing-store toast messages via lastMessage state - H7: roleLabel for all resource types MEDIUM fixes (11): - M1: identitySignatureMap cleanup on delete - M2: Now-line relative positioning - M3: Radial menu disabled item keyboard nav - M4: Radial menu stable event listener via refs - M5: cancelBooking error on missing booking - M6: PasswordRow isMasked state flag - M7: Extract shared rights into lib/sharing-rights.ts - M8: VNCtalk client server-side guard - M9: Collabora configManager instead of process.env - M10: CONFIG_ENV_MAP VNCdirectory fields - M11: SENSITIVE_CONFIG_KEYS field name unification LOW fixes (7): - L1-L3: Unused imports removed - L4: aria-labels on close, clear, search, spinner - L5-L7: Comments for intentional patterns, null guard
This commit is contained in:
@@ -33,6 +33,13 @@ export function RadialMenu({
|
||||
const [activeIndex, setActiveIndex] = useState<number>(-1);
|
||||
const [animatingIn, setAnimatingIn] = useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const activeIndexRef = useRef(activeIndex);
|
||||
const itemsRef = useRef(items);
|
||||
const onCloseRef = useRef(onClose);
|
||||
|
||||
activeIndexRef.current = activeIndex;
|
||||
itemsRef.current = items;
|
||||
onCloseRef.current = onClose;
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
@@ -51,45 +58,54 @@ export function RadialMenu({
|
||||
setActiveIndex(-1);
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const items = itemsRef.current;
|
||||
const currentIndex = activeIndexRef.current;
|
||||
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
onCloseRef.current();
|
||||
return;
|
||||
}
|
||||
if (e.key === "Enter" && activeIndex >= 0 && activeIndex < items.length) {
|
||||
e.preventDefault();
|
||||
const item = items[activeIndex];
|
||||
if (!item.disabled) {
|
||||
item.onClick();
|
||||
onClose();
|
||||
if (e.key === "Enter") {
|
||||
if (currentIndex >= 0 && currentIndex < items.length) {
|
||||
e.preventDefault();
|
||||
const item = items[currentIndex];
|
||||
if (!item.disabled) {
|
||||
item.onClick();
|
||||
onCloseRef.current();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
setActiveIndex((prev) => {
|
||||
let next = prev + 1;
|
||||
if (next >= items.length) next = 0;
|
||||
const hasEnabledItem = items.some((item) => !item.disabled);
|
||||
if (!hasEnabledItem) return -1;
|
||||
|
||||
let next = prev;
|
||||
let loops = 0;
|
||||
while (items[next]?.disabled && loops < items.length) {
|
||||
do {
|
||||
next = next + 1 >= items.length ? 0 : next + 1;
|
||||
loops++;
|
||||
}
|
||||
return next;
|
||||
} while (items[next]?.disabled && loops < items.length);
|
||||
return items[next]?.disabled ? -1 : next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
setActiveIndex((prev) => {
|
||||
let next = prev - 1;
|
||||
if (next < 0) next = items.length - 1;
|
||||
const hasEnabledItem = items.some((item) => !item.disabled);
|
||||
if (!hasEnabledItem) return -1;
|
||||
|
||||
let next = prev;
|
||||
let loops = 0;
|
||||
while (items[next]?.disabled && loops < items.length) {
|
||||
do {
|
||||
next = next - 1 < 0 ? items.length - 1 : next - 1;
|
||||
loops++;
|
||||
}
|
||||
return next;
|
||||
} while (items[next]?.disabled && loops < items.length);
|
||||
return items[next]?.disabled ? -1 : next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -97,7 +113,7 @@ export function RadialMenu({
|
||||
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => document.removeEventListener("keydown", handleKeyDown);
|
||||
}, [isOpen, activeIndex, items, onClose]);
|
||||
}, [isOpen]);
|
||||
|
||||
const radius = size / 2 - 28;
|
||||
const center = size / 2;
|
||||
|
||||
Reference in New Issue
Block a user