fix: and even more fixes for M3

This commit is contained in:
2026-04-05 19:36:31 +02:00
parent 17c4c79fd6
commit eb80e8ef19
10 changed files with 568 additions and 152 deletions

View File

@@ -1002,6 +1002,7 @@ impl BdsApp {
MediaEditorMsg::AltChanged(s) => { state.alt = s; state.is_dirty = true; }
MediaEditorMsg::CaptionChanged(s) => { state.caption = s; state.is_dirty = true; }
MediaEditorMsg::AuthorChanged(s) => { state.author = s; state.is_dirty = true; }
MediaEditorMsg::SwitchLanguage(lang) => { state.switch_language(&lang); }
MediaEditorMsg::Save => {
return self.save_media_editor(&tab_id);
}
@@ -1134,11 +1135,31 @@ impl BdsApp {
Message::PostLoaded(result) => {
match result {
Ok(post) => {
let translations = self.db.as_ref()
let mut translations = self.db.as_ref()
.and_then(|db| bds_core::db::queries::post_translation::list_post_translations_by_post(
db.conn(), &post.id,
).ok())
.unwrap_or_default();
// Published translations don't store body in DB — read from file
if let Some(ref data_dir) = self.data_dir {
for tr in &mut translations {
if tr.content.is_none() {
let rel = bds_core::util::paths::translation_file_path(
post.created_at,
&post.slug,
&tr.language,
);
let path = data_dir.join(&rel);
if let Ok(raw) = std::fs::read_to_string(&path) {
if let Ok((_fm, body)) =
bds_core::util::frontmatter::read_translation_file(&raw)
{
tr.content = Some(body);
}
}
}
}
}
let (outlinks, backlinks) = self.load_post_links(&post.id);
let state = PostEditorState::from_post(&post, &self.blog_languages, &translations, outlinks, backlinks);
self.post_editors.insert(post.id.clone(), state);
@@ -1150,7 +1171,12 @@ impl BdsApp {
Message::MediaLoaded(result) => {
match result {
Ok(media) => {
let state = MediaEditorState::from_media(&media);
let translations = self.db.as_ref()
.and_then(|db| bds_core::db::queries::media_translation::list_media_translations_by_media(
db.conn(), &media.id,
).ok())
.unwrap_or_default();
let state = MediaEditorState::from_media(&media, &self.blog_languages, &translations);
self.media_editors.insert(media.id.clone(), state);
}
Err(e) => self.notify(ToastLevel::Error, &e),
@@ -1873,13 +1899,22 @@ impl BdsApp {
fn handle_tags_msg(&mut self, msg: TagsMsg) -> Task<Message> {
// Ensure tags view state exists
if self.tags_view_state.is_none() {
let tags = if let (Some(db), Some(project)) = (&self.db, &self.active_project) {
bds_core::db::queries::tag::list_tags_by_project(db.conn(), &project.id)
.unwrap_or_default()
let (tags, counts) = if let (Some(db), Some(project)) = (&self.db, &self.active_project) {
let tags = bds_core::db::queries::tag::list_tags_by_project(db.conn(), &project.id)
.unwrap_or_default();
let posts = bds_core::db::queries::post::list_posts_by_project(db.conn(), &project.id)
.unwrap_or_default();
let mut counts = std::collections::HashMap::new();
for post in &posts {
for tag_name in &post.tags {
*counts.entry(tag_name.to_lowercase()).or_insert(0usize) += 1;
}
}
(tags, counts)
} else {
Vec::new()
(Vec::new(), std::collections::HashMap::new())
};
self.tags_view_state = Some(TagsViewState::new(tags));
self.tags_view_state = Some(TagsViewState::new(tags, counts));
}
let state = self.tags_view_state.as_mut().unwrap();
match msg {
@@ -2042,6 +2077,18 @@ impl BdsApp {
let _ = open::that(dir);
}
}
SettingsMsg::FocusSection(section) => {
// Expand the target section, collapse all others
use crate::views::settings_view::SettingsSection;
let all_others: Vec<SettingsSection> = SettingsSection::all()
.iter()
.filter(|s| **s != section)
.cloned()
.collect();
state.collapsed = all_others;
// Clear search filter to ensure section is visible
state.search_query.clear();
}
}
Task::none()
}
@@ -2104,9 +2151,29 @@ impl BdsApp {
}
}
// Load translations for translation flags bar
let translations = bds_core::db::queries::post_translation::list_post_translations_by_post(
let mut translations = bds_core::db::queries::post_translation::list_post_translations_by_post(
db.conn(), &post.id,
).unwrap_or_default();
// Published translations don't store body in DB — read from file
if let Some(ref data_dir) = self.data_dir {
for tr in &mut translations {
if tr.content.is_none() {
let rel = bds_core::util::paths::translation_file_path(
post.created_at,
&post.slug,
&tr.language,
);
let path = data_dir.join(&rel);
if let Ok(raw) = std::fs::read_to_string(&path) {
if let Ok((_fm, body)) =
bds_core::util::frontmatter::read_translation_file(&raw)
{
tr.content = Some(body);
}
}
}
}
}
let (outlinks, backlinks) = self.load_post_links(&post.id);
self.post_editors.insert(
post.id.clone(),
@@ -2123,7 +2190,10 @@ impl BdsApp {
if !self.media_editors.contains_key(&tab.id) {
match bds_core::db::queries::media::get_media_by_id(db.conn(), &tab.id) {
Ok(media) => {
self.media_editors.insert(media.id.clone(), MediaEditorState::from_media(&media));
let translations = bds_core::db::queries::media_translation::list_media_translations_by_media(
db.conn(), &media.id,
).unwrap_or_default();
self.media_editors.insert(media.id.clone(), MediaEditorState::from_media(&media, &self.blog_languages, &translations));
}
Err(e) => {
self.notify(ToastLevel::Error, &format!("Failed to load media: {e}"));
@@ -2185,17 +2255,30 @@ impl BdsApp {
TabType::Tags => {
if self.tags_view_state.is_none() {
let project_id = self.active_project.as_ref().map(|p| p.id.as_str()).unwrap_or("");
// Sync tags from posts first to ensure tags table is populated
// Import tags from file first, then sync from posts (additive only)
if let Some(ref data_dir) = self.data_dir {
let _ = bds_core::engine::tag::sync_tags_from_posts(
let _ = bds_core::engine::tag::import_tags_from_file(
db.conn(), data_dir, project_id,
);
let _ = bds_core::engine::tag::sync_tags_from_posts(
db.conn(), project_id,
);
}
let tags = bds_core::db::queries::tag::list_tags_by_project(
db.conn(),
project_id,
).unwrap_or_default();
self.tags_view_state = Some(TagsViewState::new(tags));
// Compute post counts per tag for cloud sizing
let posts = bds_core::db::queries::post::list_posts_by_project(
db.conn(), project_id,
).unwrap_or_default();
let mut tag_post_counts = std::collections::HashMap::new();
for post in &posts {
for tag_name in &post.tags {
*tag_post_counts.entry(tag_name.to_lowercase()).or_insert(0usize) += 1;
}
}
self.tags_view_state = Some(TagsViewState::new(tags, tag_post_counts));
}
}
TabType::Settings => {