From e6075f80b3f18b702f7234cb5234225e144c8b6d Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Wed, 13 May 2026 17:40:40 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20final=20review=20fixes=20=E2=80=94=20por?= =?UTF-8?q?t=20guard,=20network=20error=20handling,=20wizard=20back=20nav,?= =?UTF-8?q?=20tablist=20arrow=20keys,=20dialog=20focus=20trap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - wizard.py: wrap syslog_port int() in try/except to default 514 on non-numeric input - ContextView: add try/catch to doDelete, doDeleteFact, addFact for network errors - ContextView: arrow-key navigation for tablist (ArrowLeft/ArrowRight) - DiagnoseView: arrow-key navigation for tablist (ArrowLeft/ArrowRight) - WizardOverlay: reset current_step to last schema step when clicking 'Go back and edit' - WizardOverlay: focus trap on Tab/Shift+Tab within dialog element --- app/context/wizard.py | 5 ++- web/src/components/WizardOverlay.vue | 17 +++++++- web/src/views/ContextView.vue | 59 +++++++++++++++++++--------- web/src/views/DiagnoseView.vue | 21 ++++++++-- 4 files changed, 78 insertions(+), 24 deletions(-) diff --git a/app/context/wizard.py b/app/context/wizard.py index a741968..d323f4c 100644 --- a/app/context/wizard.py +++ b/app/context/wizard.py @@ -115,7 +115,10 @@ def apply_session(db_path: Path, session: dict[str, Any]) -> dict[str, Any]: syslog_answer = str(answers.get("syslog") or "No") if syslog_answer.startswith("Yes"): - port = int(answers.get("syslog_port") or 514) + try: + port = int(answers.get("syslog_port") or 514) + except (ValueError, TypeError): + port = 514 sources.append({"type": "syslog", "id": f"syslog:{hostname}", "port": port}) return { diff --git a/web/src/components/WizardOverlay.vue b/web/src/components/WizardOverlay.vue index bdf0cb0..521c2a4 100644 --- a/web/src/components/WizardOverlay.vue +++ b/web/src/components/WizardOverlay.vue @@ -4,6 +4,7 @@ aria-modal="true" :aria-labelledby="`wiz-heading-${currentStep?.step ?? 1}`" class="fixed inset-0 z-50 bg-surface overflow-y-auto" + :ref="(el) => { dialogRef = el as HTMLElement | null }" >
@@ -94,7 +95,7 @@ > {{ applying ? 'Saving…' : `Save ${factCount} facts and apply source config` }} -
@@ -133,6 +134,7 @@ const applying = ref(false) const applyError = ref(null) const headingRef = ref(null) const summaryRef = ref(null) +const dialogRef = ref(null) const totalSteps = computed(() => schema.value.length) const currentStep = computed(() => @@ -207,6 +209,19 @@ async function applyWizard() { } function onKeydown(e: KeyboardEvent) { + if (e.key === 'Tab') { + const focusable = dialogRef.value?.querySelectorAll( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' + ) + if (!focusable || focusable.length === 0) return + const first = focusable[0]! + const last = focusable[focusable.length - 1]! + if (e.shiftKey) { + if (document.activeElement === first) { e.preventDefault(); last.focus() } + } else { + if (document.activeElement === last) { e.preventDefault(); first.focus() } + } + } if (e.key === 'Escape') emit('close') } diff --git a/web/src/views/ContextView.vue b/web/src/views/ContextView.vue index 0847320..b8893d2 100644 --- a/web/src/views/ContextView.vue +++ b/web/src/views/ContextView.vue @@ -21,7 +21,7 @@