fix: tag editor hopefully working and fixes to test runner
This commit is contained in:
@@ -13,6 +13,8 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|
||||
|
||||
embed_templates("tags_editor_html/*")
|
||||
|
||||
@tags_sections ~w(cloud manage merge)
|
||||
|
||||
@spec assign_socket(term()) :: term()
|
||||
def assign_socket(socket) do
|
||||
assign(socket, :tags_editor, build(socket.assigns))
|
||||
@@ -198,9 +200,13 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|
||||
|
||||
@spec sync(term(), term(), term()) :: term()
|
||||
def sync(socket, reload, append_output) do
|
||||
_ = append_output
|
||||
:ok = Tags.sync_tags_json(socket.assigns.projects.active_project_id)
|
||||
reload.(socket, socket.assigns.workbench)
|
||||
case Tags.sync_tags_from_posts(socket.assigns.projects.active_project_id) do
|
||||
{:ok, _tags} -> reload.(socket, socket.assigns.workbench)
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output.(translated("Tags"), inspect(reason), nil, "error")
|
||||
|> reload.(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
@spec build(term()) :: term()
|
||||
@@ -226,6 +232,8 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|
||||
select: %{slug: template.slug, title: template.title}
|
||||
)
|
||||
|
||||
selected_section = current_tags_section(assigns)
|
||||
|
||||
%{
|
||||
tags:
|
||||
Enum.map(tags, fn tag ->
|
||||
@@ -235,7 +243,8 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|
||||
new_tag: Map.get(assigns, :tags_editor_new_tag, %{"name" => "", "color" => ""}),
|
||||
edit_draft: edit_draft,
|
||||
templates: templates,
|
||||
merge_target: Map.get(assigns, :tags_editor_merge_target, List.first(selected) || "")
|
||||
merge_target: Map.get(assigns, :tags_editor_merge_target, List.first(selected) || ""),
|
||||
selected_section: selected_section
|
||||
}
|
||||
end
|
||||
|
||||
@@ -293,6 +302,25 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|
||||
end
|
||||
end
|
||||
|
||||
defp current_tags_section(assigns) do
|
||||
assigns
|
||||
|> current_tab_meta()
|
||||
|> Map.get(:sidebar_item_id, "tags-cloud")
|
||||
|> to_string()
|
||||
|> String.replace_prefix("tags-", "")
|
||||
|> case do
|
||||
section when section in @tags_sections -> section
|
||||
_other -> "cloud"
|
||||
end
|
||||
end
|
||||
|
||||
defp current_tab_meta(assigns) do
|
||||
case Map.get(assigns, :current_tab) do
|
||||
%{type: type, id: id} -> Map.get(assigns[:tab_meta] || %{}, {type, id}, %{})
|
||||
_other -> %{}
|
||||
end
|
||||
end
|
||||
|
||||
defp tag_counts(project_id) do
|
||||
Repo.all(from post in Post, where: post.project_id == ^project_id, select: post.tags)
|
||||
|> List.flatten()
|
||||
|
||||
@@ -1,24 +1,38 @@
|
||||
<div class="tags-view-shell" data-testid="tags-editor">
|
||||
<div
|
||||
id="tags-editor-shell"
|
||||
class="tags-view-shell"
|
||||
data-testid="tags-editor"
|
||||
phx-hook="TagsSectionScroll"
|
||||
data-selected-tags-section={@tags_editor.selected_section}
|
||||
data-tags-scroll-target={"tags-section-#{@tags_editor.selected_section}"}
|
||||
>
|
||||
<div class="tags-view">
|
||||
<div class="tags-view-header">
|
||||
<h2><%= translated("Tags") %></h2>
|
||||
</div>
|
||||
|
||||
<div class="tags-view-content">
|
||||
<div class="tags-section">
|
||||
<div class="tags-section" id="tags-section-cloud">
|
||||
<div class="tags-section-header"><h3><%= translated("Tag Cloud") %></h3></div>
|
||||
<div class="tags-section-content">
|
||||
<div class="tag-cloud">
|
||||
<%= for tag <- @tags_editor.tags do %>
|
||||
<button class={["tag-cloud-item", if(tag.name in @tags_editor.selected, do: "selected"), if(tag.color, do: "has-color")]} style={tag_style(tag, @tags_editor.tags)} type="button" phx-click="toggle_tag_selection" phx-value-name={tag.name}>
|
||||
<%= tag.name %><span class="tag-count"><%= tag.count %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= if Enum.empty?(@tags_editor.tags) do %>
|
||||
<div class="tags-empty-state">
|
||||
<p><%= translated("No tags found") %></p>
|
||||
<button class="secondary" type="button" phx-click="sync_tags_editor"><%= translated("Discover") %></button>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="tag-cloud">
|
||||
<%= for tag <- @tags_editor.tags do %>
|
||||
<button class={["tag-cloud-item", if(tag.name in @tags_editor.selected, do: "selected"), if(tag.color, do: "has-color")]} style={tag_style(tag, @tags_editor.tags)} type="button" phx-click="toggle_tag_selection" phx-value-name={tag.name}>
|
||||
<%= tag.name %><span class="tag-count"><%= tag.count %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags-section">
|
||||
<div class="tags-section" id="tags-section-manage">
|
||||
<div class="tags-section-header"><h3><%= translated("Create / Edit") %></h3></div>
|
||||
<div class="tags-section-content">
|
||||
<form class="tag-create-form" phx-change="change_new_tag_editor">
|
||||
@@ -48,7 +62,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags-section">
|
||||
<div class="tags-section" id="tags-section-merge">
|
||||
<div class="tags-section-header"><h3><%= translated("Merge Tags") %></h3></div>
|
||||
<div class="tags-section-content">
|
||||
<div class="merge-form">
|
||||
@@ -64,7 +78,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags-section">
|
||||
<div class="tags-section" id="tags-section-sync">
|
||||
<div class="tags-section-header"><h3><%= translated("Sync") %></h3></div>
|
||||
<div class="tags-section-content">
|
||||
<button class="secondary" type="button" phx-click="sync_tags_editor"><%= translated("Discover") %></button>
|
||||
|
||||
@@ -830,6 +830,35 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
},
|
||||
|
||||
TagsSectionScroll: {
|
||||
mounted() {
|
||||
this.lastTargetId = null;
|
||||
this.scrollToSelectedSection();
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.scrollToSelectedSection();
|
||||
},
|
||||
|
||||
scrollToSelectedSection() {
|
||||
const targetId = this.el.dataset.tagsScrollTarget;
|
||||
|
||||
if (!targetId || targetId === this.lastTargetId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastTargetId = targetId;
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
const target = document.getElementById(targetId);
|
||||
|
||||
if (target && this.el.contains(target)) {
|
||||
target.scrollIntoView({ block: "start", behavior: "smooth" });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ChatSurface: {
|
||||
mounted() {
|
||||
this.stickToBottom = true;
|
||||
|
||||
@@ -330,6 +330,61 @@ defmodule BDS.Desktop.ShellLiveTest do
|
||||
assert html =~ ~s(data-settings-scroll-target="settings-section-ai")
|
||||
end
|
||||
|
||||
test "tags sidebar selections expose a scroll target for the tags editor" do
|
||||
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||
|
||||
_html = render_click(view, "select_view", %{"view" => "tags"})
|
||||
|
||||
html =
|
||||
view
|
||||
|> element("[data-testid='sidebar-open-item'][data-item-id='tags-merge']")
|
||||
|> render_click()
|
||||
|
||||
assert html =~ ~s(data-testid="tags-editor")
|
||||
assert html =~ ~s(phx-hook="TagsSectionScroll")
|
||||
assert html =~ ~s(data-selected-tags-section="merge")
|
||||
assert html =~ ~s(data-tags-scroll-target="tags-section-merge")
|
||||
end
|
||||
|
||||
test "tags discover materializes post tags and enables merge from the tags editor", %{
|
||||
project: project
|
||||
} do
|
||||
assert {:ok, post} =
|
||||
Posts.create_post(%{
|
||||
project_id: project.id,
|
||||
title: "Tagged Post",
|
||||
content: "Body",
|
||||
tags: ["Alpha", "Beta"]
|
||||
})
|
||||
|
||||
assert Tags.list_tags(project.id) == []
|
||||
|
||||
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
|
||||
|
||||
_html = render_click(view, "select_view", %{"view" => "tags"})
|
||||
|
||||
_html =
|
||||
view
|
||||
|> element("[data-testid='sidebar-open-item'][data-item-id='tags-cloud']")
|
||||
|> render_click()
|
||||
|
||||
html = render_click(view, "sync_tags_editor", %{})
|
||||
|
||||
assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha", "Beta"]
|
||||
assert html =~ "Alpha"
|
||||
assert html =~ "Beta"
|
||||
|
||||
_html = render_click(view, "toggle_tag_selection", %{"name" => "Alpha"})
|
||||
_html = render_click(view, "toggle_tag_selection", %{"name" => "Beta"})
|
||||
_html = render_change(view, "change_merge_target", %{"target" => "Alpha"})
|
||||
|
||||
html = render_click(view, "merge_tags_editor", %{})
|
||||
|
||||
assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha"]
|
||||
assert Repo.get!(Post, post.id).tags == ["Alpha"]
|
||||
assert html =~ "Alpha"
|
||||
end
|
||||
|
||||
test "database-backed sidebar entries require confirmation before deletion", %{
|
||||
project: project,
|
||||
temp_dir: temp_dir
|
||||
|
||||
@@ -2,6 +2,10 @@ cache_root = Path.join(System.tmp_dir!(), "bds-test-cache-#{System.unique_intege
|
||||
File.mkdir_p!(cache_root)
|
||||
Application.put_env(:bds, :project_cache_root, cache_root)
|
||||
|
||||
Enum.each(["LC_ALL", "LC_MESSAGES", "LANG"], fn variable ->
|
||||
System.put_env(variable, "en_US.UTF-8")
|
||||
end)
|
||||
|
||||
ExUnit.start()
|
||||
|
||||
ExUnit.after_suite(fn _results ->
|
||||
|
||||
Reference in New Issue
Block a user