From 7881d0922f9ec50670c94edde60a6ea26f7178db Mon Sep 17 00:00:00 2001 From: bernardhanna Date: Mon, 14 Sep 2026 11:37:14 +0100 Subject: [PATCH] Render featured activities calendar outside the Vue root. Vue mounts on
with the runtime compiler, which clears the container and rebuilds every node from the server HTML. That happens about 18ms after Livewire initialises, so the visible filters were copies carrying wire: attributes but none of Livewire's event listeners. Changing a filter produced no request at all and no error. Move the component into the existing non-vue region, which Vue never touches. Also drop indexes before their columns in two support-table migrations, since SQLite refuses to drop an indexed column and this broke rollback for the whole test suite. Co-authored-by: Cursor --- ...mail_fields_to_support_approvals_table.php | 9 ++++++++ ...or_agent_fields_to_support_cases_table.php | 7 ++++++ .../views/online-calendar/oc-index.blade.php | 8 ++++++- tests/Feature/OnlineEventsWorkflowTest.php | 22 +++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/database/migrations/2026_05_19_120000_add_gmail_fields_to_support_approvals_table.php b/database/migrations/2026_05_19_120000_add_gmail_fields_to_support_approvals_table.php index f091bd77b..be15411aa 100644 --- a/database/migrations/2026_05_19_120000_add_gmail_fields_to_support_approvals_table.php +++ b/database/migrations/2026_05_19_120000_add_gmail_fields_to_support_approvals_table.php @@ -52,6 +52,15 @@ public function down(): void return; } + // SQLite refuses to drop a column while an index still references it. + foreach (['gmail_thread_id', 'gmail_message_id', 'notify_email'] as $column) { + if (Schema::hasColumn('support_approvals', $column)) { + Schema::table('support_approvals', function (Blueprint $table) use ($column) { + $table->dropIndex('support_approvals_'.$column.'_index'); + }); + } + } + Schema::table('support_approvals', function (Blueprint $table) { $columns = array_filter([ Schema::hasColumn('support_approvals', 'gmail_thread_id') ? 'gmail_thread_id' : null, diff --git a/database/migrations/2026_06_23_090000_add_cursor_agent_fields_to_support_cases_table.php b/database/migrations/2026_06_23_090000_add_cursor_agent_fields_to_support_cases_table.php index aef3af3e7..d6cbab4a6 100644 --- a/database/migrations/2026_06_23_090000_add_cursor_agent_fields_to_support_cases_table.php +++ b/database/migrations/2026_06_23_090000_add_cursor_agent_fields_to_support_cases_table.php @@ -25,6 +25,13 @@ public function up(): void public function down(): void { + // SQLite refuses to drop a column while an index still references it. + if (Schema::hasColumn('support_cases', 'cursor_agent_id')) { + Schema::table('support_cases', function (Blueprint $table) { + $table->dropIndex('support_cases_cursor_agent_id_index'); + }); + } + Schema::table('support_cases', function (Blueprint $table) { foreach (['cursor_agent_id', 'cursor_agent_status', 'cursor_pr_url', 'live_promotion_pr_url'] as $column) { if (Schema::hasColumn('support_cases', $column)) { diff --git a/resources/views/online-calendar/oc-index.blade.php b/resources/views/online-calendar/oc-index.blade.php index 308c5ab72..0bde1ba05 100644 --- a/resources/views/online-calendar/oc-index.blade.php +++ b/resources/views/online-calendar/oc-index.blade.php @@ -49,9 +49,15 @@ class="absolute top-0 right-0 h-full max-w-[calc(70vw)] object-cover hidden md:b + +@endsection +{{-- Rendered outside
on purpose. Vue mounts there with the runtime + compiler, which clears the container and rebuilds every node from the server HTML, + discarding Livewire's event listeners so the filters stop responding. --}} +@section('non-vue-content') +
@livewire('online-calendar') -
@endsection diff --git a/tests/Feature/OnlineEventsWorkflowTest.php b/tests/Feature/OnlineEventsWorkflowTest.php index d43fe3745..53c764c09 100644 --- a/tests/Feature/OnlineEventsWorkflowTest.php +++ b/tests/Feature/OnlineEventsWorkflowTest.php @@ -256,6 +256,28 @@ public function featured_activities_page_shows_all_upcoming_open_online_events() ->assertDontSee($pendingEvent->title); } + #[Test] + public function featured_activities_calendar_renders_outside_the_vue_root(): void + { + $this->seed('RolesAndPermissionsSeeder'); + + $html = $this->get('/featured-activities')->assertStatus(200)->getContent(); + + $nonVueStart = strpos($html, '
assertNotFalse($nonVueStart, 'Layout should expose the non-vue region.'); + $this->assertNotFalse($component, 'Calendar component should render.'); + + // Vue mounts on
with the runtime compiler, which clears the + // container and rebuilds every node, stripping Livewire's event listeners. + $this->assertGreaterThan( + $nonVueStart, + $component, + 'The calendar must render inside
, otherwise Vue destroys its Livewire bindings and the filters stop responding.' + ); + } + #[Test] public function featured_activities_month_filter_only_shows_events_for_selected_month(): void {