From cf69cb7b0527a34fd5054caf1db56069f201a067 Mon Sep 17 00:00:00 2001 From: Per Stark Date: Fri, 12 Jun 2026 15:08:51 +0200 Subject: [PATCH] fix: don't close modal on inner HTMX requests. changelog --- CHANGELOG.md | 1 + html-router/assets/style.css | 93 ------------------- html-router/templates/modal_base.html | 2 +- html-router/tests/router_integration.rs | 16 ++++ .../tests/snapshots/new_entity_modal.snap | 3 +- 5 files changed, 20 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e1520..f088ea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased - Performance: ingestion skips per-task index rebuild; worker runs scheduled `REBUILD INDEX` (default every 24h via `index_rebuild_interval_secs`, `0` disables) +- Fix: regression re suggestion of relationships ## 1.0.3 (2026-06-12) - Search: filter results by type — knowledge entities, ingested content, or both diff --git a/html-router/assets/style.css b/html-router/assets/style.css index fd43572..a9691cc 100644 --- a/html-router/assets/style.css +++ b/html-router/assets/style.css @@ -285,37 +285,6 @@ } } } - .drawer-open { - > .drawer-side { - overflow-y: auto; - } - > .drawer-toggle { - display: none; - & ~ .drawer-side { - pointer-events: auto; - visibility: visible; - position: sticky; - display: block; - width: auto; - overscroll-behavior: auto; - opacity: 100%; - & > .drawer-overlay { - cursor: default; - background-color: transparent; - } - & > *:not(.drawer-overlay) { - translate: 0%; - [dir="rtl"] & { - translate: 0%; - } - } - } - &:checked ~ .drawer-side { - pointer-events: auto; - visibility: visible; - } - } - } .drawer-toggle { position: fixed; height: calc(0.25rem * 0); @@ -1074,22 +1043,6 @@ grid-row-start: 1; min-width: calc(0.25rem * 0); } - .chat-image { - grid-row: span 2 / span 2; - align-self: flex-end; - } - .chat-footer { - grid-row-start: 3; - display: flex; - gap: calc(0.25rem * 1); - font-size: 0.6875rem; - } - .chat-header { - grid-row-start: 1; - display: flex; - gap: calc(0.25rem * 1); - font-size: 0.6875rem; - } .container { width: 100%; @media (width >= 40rem) { @@ -1796,9 +1749,6 @@ .w-10 { width: calc(var(--spacing) * 10); } - .w-11 { - width: calc(var(--spacing) * 11); - } .w-11\/12 { width: calc(11/12 * 100%); } @@ -1862,9 +1812,6 @@ .flex-none { flex: none; } - .flex-shrink { - flex-shrink: 1; - } .flex-shrink-0 { flex-shrink: 0; } @@ -1877,13 +1824,6 @@ .grow { flex-grow: 1; } - .border-collapse { - border-collapse: collapse; - } - .-translate-y-1 { - --tw-translate-y: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1956,9 +1896,6 @@ .justify-start { justify-content: flex-start; } - .gap-0 { - gap: calc(var(--spacing) * 0); - } .gap-0\.5 { gap: calc(var(--spacing) * 0.5); } @@ -2091,9 +2028,6 @@ .border-base-200 { border-color: var(--color-base-200); } - .border-base-content { - border-color: var(--color-base-content); - } .border-base-content\/10 { border-color: var(--color-base-content); @supports (color: color-mix(in lab, red, red)) { @@ -2130,9 +2064,6 @@ .bg-transparent { background-color: transparent; } - .bg-warning { - background-color: var(--color-warning); - } .bg-warning\/10 { background-color: var(--color-warning); @supports (color: color-mix(in lab, red, red)) { @@ -2151,9 +2082,6 @@ .loading-spinner { mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='black' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg transform-origin='center'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 12 12' to='360 12 12' dur='2s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dasharray' values='0,150;42,150;42,150' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3Canimate attributeName='stroke-dashoffset' values='0;-16;-59' keyTimes='0;0.475;1' dur='1.5s' repeatCount='indefinite'/%3E%3C/circle%3E%3C/g%3E%3C/svg%3E"); } - .mask-repeat { - mask-repeat: repeat; - } .fill-current { fill: currentcolor; } @@ -2184,9 +2112,6 @@ .p-8 { padding: calc(var(--spacing) * 8); } - .px-1 { - padding-inline: calc(var(--spacing) * 1); - } .px-1\.5 { padding-inline: calc(var(--spacing) * 1.5); } @@ -2341,9 +2266,6 @@ --tw-tracking: var(--tracking-widest); letter-spacing: var(--tracking-widest); } - .text-wrap { - text-wrap: wrap; - } .break-words { overflow-wrap: break-word; } @@ -2410,17 +2332,6 @@ .italic { font-style: italic; } - .underline { - text-decoration-line: underline; - } - .swap-active { - .swap-off { - opacity: 0%; - } - .swap-on { - opacity: 100%; - } - } .opacity-0 { opacity: 0%; } @@ -2514,10 +2425,6 @@ --tw-duration: 300ms; transition-duration: 300ms; } - .ease-in-out { - --tw-ease: var(--ease-in-out); - transition-timing-function: var(--ease-in-out); - } .ease-out { --tw-ease: var(--ease-out); transition-timing-function: var(--ease-out); diff --git a/html-router/templates/modal_base.html b/html-router/templates/modal_base.html index 08aacd8..8ed5359 100644 --- a/html-router/templates/modal_base.html +++ b/html-router/templates/modal_base.html @@ -12,7 +12,7 @@ {# Default: one outer #modal_form. Modals with multiple forms (scratchpad editor) override modal_form_open / modal_form_close — nested
is invalid HTML. #} - {% block modal_form_open %}{% endblock %} + {% block modal_form_open %}{% endblock %}
{% block modal_content %}{% endblock %}
diff --git a/html-router/tests/router_integration.rs b/html-router/tests/router_integration.rs index 0f8347f..f503422 100644 --- a/html-router/tests/router_integration.rs +++ b/html-router/tests/router_integration.rs @@ -333,6 +333,22 @@ async fn snapshot_new_entity_modal() { snapshot_settings().bind(|| insta::assert_snapshot!("new_entity_modal", body)); } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn modal_form_after_request_ignores_inner_htmx_requests() { + let (app, db) = build_test_app().await; + let cookie = seeded_cookie(&app, &db).await; + let modal = get_html(&app, "/knowledge-entity/new", Some(&cookie)).await; + + // Inner buttons (e.g. Suggest Relationships) bubble htmx:afterRequest to + // #modal_form; closing must only run when the form itself submitted. + assert!( + modal.contains( + r#"hx-on::after-request="if(event.detail.successful && event.detail.elt === event.currentTarget) document.getElementById('body_modal').close()"# + ), + "#modal_form should ignore bubbled after-request events from child elements" + ); +} + async fn sign_in(app: &Router, email: &str, password: &str) -> String { let response = app .clone() diff --git a/html-router/tests/snapshots/new_entity_modal.snap b/html-router/tests/snapshots/new_entity_modal.snap index 1587860..71a51fe 100644 --- a/html-router/tests/snapshots/new_entity_modal.snap +++ b/html-router/tests/snapshots/new_entity_modal.snap @@ -1,5 +1,6 @@ --- source: html-router/tests/router_integration.rs +assertion_line: 333 expression: body --- @@ -18,7 +19,7 @@ expression: body -