feat: fix author search, add edit modals, settings tabs & search resync

- Fix Meilisearch indexing to use authors[] array instead of scalar author field
- Join series_metadata to include series-level authors in search documents
- Configure searchable attributes (title, authors, series) in Meilisearch
- Convert EditSeriesForm and EditBookForm from inline forms to modals
- Add tabbed navigation (General / Integrations) to Settings page
- Add Force Search Resync button (POST /settings/search/resync)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 10:45:36 +01:00
parent a675dcd2a4
commit 4be8177683
8 changed files with 571 additions and 347 deletions

View File

@@ -42,6 +42,7 @@ pub fn settings_routes() -> Router<AppState> {
.route("/settings/cache/clear", post(clear_cache))
.route("/settings/cache/stats", get(get_cache_stats))
.route("/settings/thumbnail/stats", get(get_thumbnail_stats))
.route("/settings/search/resync", post(force_search_resync))
}
/// List all settings
@@ -324,3 +325,27 @@ pub async fn get_thumbnail_stats(State(_state): State<AppState>) -> Result<Json<
Ok(Json(stats))
}
/// Force a full Meilisearch resync by resetting the sync timestamp
#[utoipa::path(
post,
path = "/settings/search/resync",
tag = "settings",
responses(
(status = 200, description = "Resync scheduled"),
(status = 401, description = "Unauthorized"),
),
security(("Bearer" = []))
)]
pub async fn force_search_resync(
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
sqlx::query("UPDATE sync_metadata SET last_meili_sync = NULL WHERE id = 1")
.execute(&state.pool)
.await?;
Ok(Json(serde_json::json!({
"success": true,
"message": "Search resync scheduled. The indexer will perform a full sync on its next cycle."
})))
}