fix: don't close modal on inner HTMX requests.

changelog
This commit is contained in:
Per Stark
2026-06-12 15:08:51 +02:00
parent ead17530bd
commit cf69cb7b05
5 changed files with 20 additions and 95 deletions
+1
View File
@@ -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
-93
View File
@@ -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);
+1 -1
View File
@@ -12,7 +12,7 @@
{# Default: one outer #modal_form. Modals with multiple forms (scratchpad editor)
override modal_form_open / modal_form_close — nested <form> is invalid HTML. #}
{% block modal_form_open %}<form id="modal_form" hx-on::after-request="if(event.detail.successful) document.getElementById('body_modal').close()" {% block form_attributes %}{% endblock %}>{% endblock %}
{% block modal_form_open %}<form id="modal_form" hx-on::after-request="if(event.detail.successful && event.detail.elt === event.currentTarget) document.getElementById('body_modal').close()" {% block form_attributes %}{% endblock %}>{% endblock %}
<div class="flex flex-col flex-1 gap-5">
{% block modal_content %}{% endblock %}
</div>
+16
View File
@@ -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()
@@ -1,5 +1,6 @@
---
source: html-router/tests/router_integration.rs
assertion_line: 333
expression: body
---
<dialog id="body_modal" class="modal">
@@ -18,7 +19,7 @@ expression: body
</button>
<form id="modal_form" hx-on::after-request="if(event.detail.successful) document.getElementById('body_modal').close()"
<form id="modal_form" hx-on::after-request="if(event.detail.successful && event.detail.elt === event.currentTarget) document.getElementById('body_modal').close()"
hx-post="/knowledge-entity"
hx-target="#knowledge_pane"
hx-swap="outerHTML"