fix: fixed import action for orphaned files

This commit is contained in:
2026-05-02 11:08:33 +02:00
parent 45040f9f66
commit a4ea24faa2
4 changed files with 160 additions and 2 deletions

View File

@@ -96,7 +96,10 @@ defmodule BDS.Posts.RebuildFromFiles do
Slugs.unique_for_import(project_id, Map.fetch!(rebuild_file.fields, "slug")) Slugs.unique_for_import(project_id, Map.fetch!(rebuild_file.fields, "slug"))
) )
{:ok, upsert_post_from_rebuild_file(project_id, %{rebuild_file | fields: fields})} {:ok,
upsert_post_from_rebuild_file(project_id, %{rebuild_file | fields: fields},
sync_embeddings: false
)}
end end
end end
else else

View File

@@ -8223,7 +8223,7 @@ button.import-taxonomy-pill {
line-height: 1; line-height: 1;
padding: 0 6px; padding: 0 6px;
flex-shrink: 0; flex-shrink: 0;
opacity: 0; opacity: 1;
transition: opacity 0.15s, color 0.15s; transition: opacity 0.15s, color 0.15s;
} }

View File

@@ -64,6 +64,28 @@ defmodule BDS.Desktop.ShellCommandsTest do
end end
end end
defmodule BlockingEmbeddingBackend do
@behaviour BDS.Embeddings.Backend
@impl true
def model_info do
%{model_id: "blocking/test", dimensions: 384}
end
@impl true
def embed(_text, _opts) do
if test_pid = Application.get_env(:bds, :embedding_test_pid) do
send(test_pid, {:embedding_started, self()})
end
receive do
:release_embedding -> {:ok, List.duplicate(0.0, 384)}
after
5_000 -> {:ok, List.duplicate(0.0, 384)}
end
end
end
setup do setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo) :ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()}) Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()})
@@ -418,6 +440,122 @@ defmodule BDS.Desktop.ShellCommandsTest do
:completed :completed
end end
test "import_metadata_diff_orphans imports paired post translations before any embedding work can stall the task",
%{project: project, temp_dir: temp_dir} do
original_embeddings = Application.get_env(:bds, :embeddings)
original_tasks = Application.get_env(:bds, :tasks, [])
original_test_pid = Application.get_env(:bds, :embedding_test_pid)
Application.put_env(:bds, :embeddings, backend: BlockingEmbeddingBackend)
Application.put_env(:bds, :embedding_test_pid, self())
Application.put_env(:bds, :tasks, Keyword.put(original_tasks, :progress_throttle_ms, 0))
on_exit(fn ->
release_blocking_embeddings()
Enum.each(BDS.Tasks.list_running_tasks(), &BDS.Tasks.cancel_task(&1.id))
_ = BDS.Tasks.clear_finished()
if original_embeddings == nil do
Application.delete_env(:bds, :embeddings)
else
Application.put_env(:bds, :embeddings, original_embeddings)
end
if original_test_pid == nil do
Application.delete_env(:bds, :embedding_test_pid)
else
Application.put_env(:bds, :embedding_test_pid, original_test_pid)
end
Application.put_env(:bds, :tasks, original_tasks)
end)
assert {:ok, _metadata} =
BDS.Metadata.update_project_metadata(project.id, %{semantic_similarity_enabled: true})
post_orphan_path = "posts/2026/04/shell-orphan-post.md"
post_translation_orphan_path = "posts/2026/04/shell-orphan-post.es.md"
File.mkdir_p!(Path.join([temp_dir, "posts", "2026", "04"]))
File.write!(
Path.join(temp_dir, post_orphan_path),
[
"---",
"id: shell-orphan-post",
"title: Shell Orphan Post",
"slug: shell-orphan-post",
"status: published",
"createdAt: 1",
"updatedAt: 1",
"publishedAt: 1",
"tags:",
"categories:",
"---",
"Orphan shell body",
""
]
|> Enum.join("\n")
)
File.write!(
Path.join(temp_dir, post_translation_orphan_path),
[
"---",
"id: shell-orphan-post-es",
"translationFor: shell-orphan-post",
"language: es",
"title: Traduccion huerfana",
"excerpt: Resumen huerfano",
"status: published",
"createdAt: 1",
"updatedAt: 1",
"publishedAt: 1",
"---",
"Contenido huerfano",
""
]
|> Enum.join("\n")
)
assert {:ok, result} =
ShellCommands.execute("import_metadata_diff_orphans", %{
"orphans" => [
%{"file_path" => post_orphan_path},
%{"file_path" => post_translation_orphan_path}
]
})
progressed =
wait_for_task(
result.task_id,
fn task ->
task.status in [:running, :completed] and is_number(task.progress) and task.progress > 0.2 and
Repo.get_by(BDS.Posts.Post, project_id: project.id, file_path: post_orphan_path) != nil and
Repo.get_by(BDS.Posts.Translation,
project_id: project.id,
file_path: post_translation_orphan_path
) != nil
end,
1_000
)
assert progressed.status in [:running, :completed]
assert is_number(progressed.progress)
assert progressed.progress > 0.2
assert Repo.get_by(BDS.Posts.Post, project_id: project.id, file_path: post_orphan_path)
assert Repo.get_by(BDS.Posts.Translation,
project_id: project.id,
file_path: post_translation_orphan_path
)
release_blocking_embeddings()
assert wait_for_task(result.task_id, &(&1.status == :completed and &1.progress == 1.0), 5_000).status ==
:completed
end
test "find_duplicates queues a tracked embeddings task and returns the report as an editor payload" do test "find_duplicates queues a tracked embeddings task and returns the report as an editor payload" do
assert {:ok, result} = ShellCommands.execute("find_duplicates") assert {:ok, result} = ShellCommands.execute("find_duplicates")
@@ -821,6 +959,16 @@ defmodule BDS.Desktop.ShellCommandsTest do
end end
end end
defp release_blocking_embeddings do
receive do
{:embedding_started, pid} ->
send(pid, :release_embedding)
release_blocking_embeddings()
after
0 -> :ok
end
end
defp configure_auto_translation_test_runtime do defp configure_auto_translation_test_runtime do
assert {:ok, _endpoint} = assert {:ok, _endpoint} =
AI.put_endpoint(:online, %{ AI.put_endpoint(:online, %{

View File

@@ -193,6 +193,13 @@ defmodule BDS.UI.ShellTest do
assert template =~ "tab-dirty-indicator" assert template =~ "tab-dirty-indicator"
end end
test "desktop shell keeps sidebar delete buttons visible in the default state" do
css = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.css")
assert Regex.match?(~r/\.sidebar-delete-button\s*\{[^}]*opacity:\s*1;/s, css)
refute Regex.match?(~r/\.sidebar-delete-button\s*\{[^}]*opacity:\s*0;/s, css)
end
test "desktop shell css keeps the old activity bar active marker contrast" do test "desktop shell css keeps the old activity bar active marker contrast" do
css = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.css") css = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.css")