changed tags editor into live component

This commit is contained in:
2026-05-03 09:03:54 +02:00
parent eb8f5698e3
commit 6c7fde6b95
5 changed files with 233 additions and 202 deletions

View File

@@ -182,10 +182,6 @@ defmodule BDS.Desktop.ShellLive do
|> assign(:settings_editor_new_category, "") |> assign(:settings_editor_new_category, "")
|> assign(:style_editor_theme, nil) |> assign(:style_editor_theme, nil)
|> assign(:style_editor_preview_mode, "auto") |> assign(:style_editor_preview_mode, "auto")
|> assign(:tags_editor_selected, [])
|> assign(:tags_editor_new_tag, %{"name" => "", "color" => ""})
|> assign(:tags_editor_edit_draft, %{})
|> assign(:tags_editor_merge_target, "")
|> assign(:script_editor_drafts, %{}) |> assign(:script_editor_drafts, %{})
|> assign(:template_editor_drafts, %{}) |> assign(:template_editor_drafts, %{})
|> assign(:chat_editor_inputs, %{}) |> assign(:chat_editor_inputs, %{})
@@ -682,42 +678,6 @@ defmodule BDS.Desktop.ShellLive do
{:noreply, MenuEditor.handle_keydown(socket, key, &reload_shell/2)} {:noreply, MenuEditor.handle_keydown(socket, key, &reload_shell/2)}
end end
def handle_event("toggle_tag_selection", %{"name" => tag_name}, socket) do
{:noreply, TagsEditor.toggle_selection(socket, tag_name, &reload_shell/2)}
end
def handle_event("change_new_tag_editor", %{"new_tag" => params}, socket) do
{:noreply, TagsEditor.update_new_tag(socket, params, &reload_shell/2)}
end
def handle_event("create_tag_editor", _params, socket) do
{:noreply, TagsEditor.create_tag(socket, &reload_shell/2, &append_output_entry/5)}
end
def handle_event("change_edit_tag_editor", %{"edit_tag" => params}, socket) do
{:noreply, TagsEditor.update_edit_tag(socket, params, &reload_shell/2)}
end
def handle_event("save_tag_editor", _params, socket) do
{:noreply, TagsEditor.save_tag(socket, &reload_shell/2, &append_output_entry/5)}
end
def handle_event("delete_tag_editor", _params, socket) do
{:noreply, TagsEditor.delete_selected(socket, &reload_shell/2, &append_output_entry/5)}
end
def handle_event("change_merge_target", %{"target" => target}, socket) do
{:noreply, TagsEditor.update_merge_target(socket, target, &reload_shell/2)}
end
def handle_event("merge_tags_editor", _params, socket) do
{:noreply, TagsEditor.merge_selected(socket, &reload_shell/2, &append_output_entry/5)}
end
def handle_event("sync_tags_editor", _params, socket) do
{:noreply, TagsEditor.sync(socket, &reload_shell/2, &append_output_entry/5)}
end
def handle_event("change_script_editor", %{"script_editor" => params}, socket) do def handle_event("change_script_editor", %{"script_editor" => params}, socket) do
{:noreply, CodeEntityEditor.update_script(socket, params, &reload_shell/2)} {:noreply, CodeEntityEditor.update_script(socket, params, &reload_shell/2)}
end end
@@ -1483,6 +1443,14 @@ defmodule BDS.Desktop.ShellLive do
end end
end end
def handle_info({:tags_editor_output, title, message, level}, socket) do
{:noreply, append_output_entry(socket, title, message, nil, level)}
end
def handle_info(:tags_changed, socket) do
{:noreply, reload_shell(socket, socket.assigns.workbench)}
end
@impl true @impl true
def render(assigns) do def render(assigns) do
UILocale.put(assigns.page_language) UILocale.put(assigns.page_language)
@@ -1555,7 +1523,6 @@ defmodule BDS.Desktop.ShellLive do
|> assign_media_editor() |> assign_media_editor()
|> assign_settings_editor() |> assign_settings_editor()
|> assign_menu_editor() |> assign_menu_editor()
|> assign_tags_editor()
|> assign_code_entity_editor() |> assign_code_entity_editor()
|> assign_chat_editor() |> assign_chat_editor()
|> assign_import_editor() |> assign_import_editor()
@@ -1617,10 +1584,6 @@ defmodule BDS.Desktop.ShellLive do
MenuEditor.assign_socket(socket) MenuEditor.assign_socket(socket)
end end
defp assign_tags_editor(socket) do
TagsEditor.assign_socket(socket)
end
defp assign_code_entity_editor(socket) do defp assign_code_entity_editor(socket) do
CodeEntityEditor.assign_socket(socket) CodeEntityEditor.assign_socket(socket)
end end
@@ -1801,7 +1764,8 @@ defmodule BDS.Desktop.ShellLive do
end end
defp save_current_tab(%{assigns: %{current_tab: %{type: :tags}}} = socket) do defp save_current_tab(%{assigns: %{current_tab: %{type: :tags}}} = socket) do
TagsEditor.save_tag(socket, &reload_shell/2, &append_output_entry/5) send_update(TagsEditor, id: "tags-editor", action: :save)
socket
end end
defp save_current_tab(%{assigns: %{current_tab: %{type: :scripts}}} = socket) do defp save_current_tab(%{assigns: %{current_tab: %{type: :scripts}}} = socket) do

View File

@@ -397,8 +397,8 @@
<% @current_tab.type == :menu_editor and @menu_editor -> %> <% @current_tab.type == :menu_editor and @menu_editor -> %>
<MenuEditor.menu_editor menu_editor={@menu_editor} /> <MenuEditor.menu_editor menu_editor={@menu_editor} />
<% @current_tab.type == :tags and @tags_editor -> %> <% @current_tab.type == :tags and @current_project -> %>
<TagsEditor.tags_editor tags_editor={@tags_editor} /> <.live_component module={TagsEditor} id="tags-editor" project_id={@current_project.id} current_tab={@current_tab} tab_meta={@tab_meta} />
<% @current_tab.type == :scripts and @script_editor -> %> <% @current_tab.type == :scripts and @script_editor -> %>
<CodeEntityEditor.script_editor script_editor={@script_editor} /> <CodeEntityEditor.script_editor script_editor={@script_editor} />

View File

@@ -1,12 +1,13 @@
defmodule BDS.Desktop.ShellLive.TagsEditor do defmodule BDS.Desktop.ShellLive.TagsEditor do
@moduledoc false @moduledoc false
use Phoenix.Component use Phoenix.LiveComponent
import Ecto.Query import Ecto.Query
alias BDS.Desktop.ShellData
alias BDS.{Repo, Tags} alias BDS.{Repo, Tags}
alias BDS.Desktop.ShellData
alias BDS.Desktop.UILocale
alias BDS.Posts.Post alias BDS.Posts.Post
alias BDS.Tags.Tag alias BDS.Tags.Tag
alias BDS.Templates.Template alias BDS.Templates.Template
@@ -15,14 +16,37 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
@tags_sections ~w(cloud manage merge) @tags_sections ~w(cloud manage merge)
@spec assign_socket(term()) :: term() @spec update(map(), Phoenix.LiveView.Socket.t()) :: {:ok, Phoenix.LiveView.Socket.t()}
def assign_socket(socket) do @impl true
assign(socket, :tags_editor, build(socket.assigns)) def update(%{action: :save} = assigns, socket) do
socket =
socket
|> assign(Map.drop(assigns, [:action]))
|> do_save()
{:ok, socket}
end end
@spec toggle_selection(term(), term(), term()) :: term() def update(assigns, socket) do
def toggle_selection(socket, tag_name, reload) do socket =
selected = Map.get(socket.assigns, :tags_editor_selected, []) socket
|> assign(assigns)
|> load_data()
{:ok, socket}
end
@spec render(map()) :: Phoenix.LiveView.Rendered.t()
@impl true
def render(assigns) do
tags_editor(assigns)
end
@spec handle_event(String.t(), map(), Phoenix.LiveView.Socket.t()) ::
{:noreply, Phoenix.LiveView.Socket.t()}
@impl true
def handle_event("toggle_tag_selection", %{"name" => tag_name}, socket) do
selected = socket.assigns.tags_editor.selected
next_selected = next_selected =
if tag_name in selected do if tag_name in selected do
@@ -31,26 +55,27 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
selected ++ [tag_name] selected ++ [tag_name]
end end
socket =
socket socket
|> assign(:tags_editor_selected, next_selected) |> put_in_tags_editor([:selected], next_selected)
|> maybe_seed_edit_draft(next_selected) |> maybe_seed_edit_draft(socket.assigns.project_id, next_selected)
|> reload.(socket.assigns.workbench)
{:noreply, socket}
end end
@spec update_new_tag(term(), term(), term()) :: term() def handle_event("change_new_tag_editor", %{"new_tag" => params}, socket) do
def update_new_tag(socket, params, reload) do tags_editor =
socket Map.put(socket.assigns.tags_editor, :new_tag, %{
|> assign(:tags_editor_new_tag, %{
"name" => Map.get(params, "name", ""), "name" => Map.get(params, "name", ""),
"color" => Map.get(params, "color", "") "color" => Map.get(params, "color", "")
}) })
|> reload.(socket.assigns.workbench)
{:noreply, assign(socket, :tags_editor, tags_editor)}
end end
@spec create_tag(term(), term(), term()) :: term() def handle_event("create_tag_editor", _params, socket) do
def create_tag(socket, reload, append_output) do project_id = socket.assigns.project_id
project_id = socket.assigns.projects.active_project_id draft = socket.assigns.tags_editor.new_tag
draft = Map.get(socket.assigns, :tags_editor_new_tag, %{})
case Tags.create_tag(%{ case Tags.create_tag(%{
project_id: project_id, project_id: project_id,
@@ -58,115 +83,83 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
color: blank_to_nil(Map.get(draft, "color")) color: blank_to_nil(Map.get(draft, "color"))
}) do }) do
{:ok, _tag} -> {:ok, _tag} ->
notify_parent(:tags_changed)
socket socket
|> assign(:tags_editor_new_tag, %{"name" => "", "color" => ""}) |> put_in_tags_editor([:new_tag], %{"name" => "", "color" => ""})
|> reload.(socket.assigns.workbench) |> load_data()
|> noreply()
{:error, reason} -> {:error, reason} ->
socket notify_output(translated("Tags"), inspect(reason), "error")
|> append_output.(translated("Tags"), inspect(reason), nil, "error") {:noreply, socket}
|> reload.(socket.assigns.workbench)
end end
end end
@spec update_edit_tag(term(), term(), term()) :: term() def handle_event("change_edit_tag_editor", %{"edit_tag" => params}, socket) do
def update_edit_tag(socket, params, reload) do tags_editor =
socket Map.put(socket.assigns.tags_editor, :edit_draft, %{
|> assign(:tags_editor_edit_draft, %{
"name" => Map.get(params, "name", ""), "name" => Map.get(params, "name", ""),
"color" => Map.get(params, "color", ""), "color" => Map.get(params, "color", ""),
"post_template_slug" => Map.get(params, "post_template_slug", "") "post_template_slug" => Map.get(params, "post_template_slug", "")
}) })
|> reload.(socket.assigns.workbench)
{:noreply, assign(socket, :tags_editor, tags_editor)}
end end
@spec save_tag(term(), term(), term()) :: term() def handle_event("save_tag_editor", _params, socket) do
def save_tag(socket, reload, append_output) do {:noreply, do_save(socket)}
selected = Map.get(socket.assigns, :tags_editor_selected, []) end
draft = Map.get(socket.assigns, :tags_editor_edit_draft, %{})
case selected do def handle_event("delete_tag_editor", _params, socket) do
case socket.assigns.tags_editor.selected do
[tag_name] -> [tag_name] ->
case Repo.get_by(Tag, case Repo.get_by(Tag,
project_id: socket.assigns.projects.active_project_id, project_id: socket.assigns.project_id,
name: tag_name name: tag_name
) do ) do
nil -> nil ->
reload.(socket, socket.assigns.workbench) {:noreply, socket}
%Tag{} = tag ->
with {:ok, _updated_tag} <-
Tags.update_tag(tag.id, %{
color: blank_to_nil(Map.get(draft, "color")),
post_template_slug: blank_to_nil(Map.get(draft, "post_template_slug"))
}),
{:ok, renamed_tag} <- maybe_rename_tag(tag, Map.get(draft, "name", tag.name)) do
socket
|> assign(:tags_editor_selected, [renamed_tag.name])
|> maybe_seed_edit_draft([renamed_tag.name])
|> reload.(socket.assigns.workbench)
else
{:error, reason} ->
socket
|> append_output.(translated("Tags"), inspect(reason), nil, "error")
|> reload.(socket.assigns.workbench)
end
end
_other ->
reload.(socket, socket.assigns.workbench)
end
end
@spec delete_selected(term(), term(), term()) :: term()
def delete_selected(socket, reload, append_output) do
case Map.get(socket.assigns, :tags_editor_selected, []) do
[tag_name] ->
case Repo.get_by(Tag,
project_id: socket.assigns.projects.active_project_id,
name: tag_name
) do
nil ->
reload.(socket, socket.assigns.workbench)
%Tag{} = tag -> %Tag{} = tag ->
case Tags.delete_tag(tag.id) do case Tags.delete_tag(tag.id) do
{:ok, _deleted} -> {:ok, _deleted} ->
notify_parent(:tags_changed)
socket socket
|> assign(:tags_editor_selected, []) |> put_in_tags_editor([:selected], [])
|> assign(:tags_editor_edit_draft, %{}) |> put_in_tags_editor([:edit_draft], %{})
|> reload.(socket.assigns.workbench) |> load_data()
|> noreply()
{:error, reason} -> {:error, reason} ->
socket notify_output(translated("Tags"), inspect(reason), "error")
|> append_output.(translated("Tags"), inspect(reason), nil, "error") {:noreply, socket}
|> reload.(socket.assigns.workbench)
end end
end end
_other -> _other ->
reload.(socket, socket.assigns.workbench) {:noreply, socket}
end end
end end
@spec update_merge_target(term(), term(), term()) :: term() def handle_event("change_merge_target", %{"target" => target}, socket) do
def update_merge_target(socket, target, reload) do tags_editor =
socket Map.put(socket.assigns.tags_editor, :merge_target, to_string(target || ""))
|> assign(:tags_editor_merge_target, to_string(target || ""))
|> reload.(socket.assigns.workbench) {:noreply, assign(socket, :tags_editor, tags_editor)}
end end
@spec merge_selected(term(), term(), term()) :: term() def handle_event("merge_tags_editor", _params, socket) do
def merge_selected(socket, reload, append_output) do selected = socket.assigns.tags_editor.selected
selected = Map.get(socket.assigns, :tags_editor_selected, []) target_name = socket.assigns.tags_editor.merge_target
target_name = Map.get(socket.assigns, :tags_editor_merge_target, "")
cond do cond do
length(selected) < 2 or target_name == "" -> length(selected) < 2 or target_name == "" ->
reload.(socket, socket.assigns.workbench) {:noreply, socket}
true -> true ->
project_id = socket.assigns.projects.active_project_id project_id = socket.assigns.project_id
tags = tags =
Repo.all( Repo.all(
@@ -178,51 +171,90 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
case target do case target do
nil -> nil ->
reload.(socket, socket.assigns.workbench) {:noreply, socket}
_target -> _target ->
case Tags.merge_tags(Enum.map(sources, & &1.id), target.id) do case Tags.merge_tags(Enum.map(sources, & &1.id), target.id) do
{:ok, _merged} -> {:ok, _merged} ->
notify_parent(:tags_changed)
socket socket
|> assign(:tags_editor_selected, [target.name]) |> put_in_tags_editor([:selected], [target.name])
|> assign(:tags_editor_merge_target, target.name) |> put_in_tags_editor([:merge_target], target.name)
|> maybe_seed_edit_draft([target.name]) |> maybe_seed_edit_draft(project_id, [target.name])
|> reload.(socket.assigns.workbench) |> load_data()
|> noreply()
{:error, reason} -> {:error, reason} ->
socket notify_output(translated("Tags"), inspect(reason), "error")
|> append_output.(translated("Tags"), inspect(reason), nil, "error") {:noreply, socket}
|> reload.(socket.assigns.workbench)
end end
end end
end end
end end
@spec sync(term(), term(), term()) :: term() def handle_event("sync_tags_editor", _params, socket) do
def sync(socket, reload, append_output) do case Tags.sync_tags_from_posts(socket.assigns.project_id) do
case Tags.sync_tags_from_posts(socket.assigns.projects.active_project_id) do {:ok, _tags} ->
{:ok, _tags} -> reload.(socket, socket.assigns.workbench) notify_parent(:tags_changed)
{:noreply, load_data(socket)}
{:error, reason} -> {:error, reason} ->
socket notify_output(translated("Tags"), inspect(reason), "error")
|> append_output.(translated("Tags"), inspect(reason), nil, "error") {:noreply, socket}
|> reload.(socket.assigns.workbench)
end end
end end
@spec build(term()) :: term() defp do_save(socket) do
def build(%{current_tab: %{type: :tags}} = assigns) do selected = socket.assigns.tags_editor.selected
project_id = assigns.projects.active_project_id draft = socket.assigns.tags_editor.edit_draft
project_id = socket.assigns.project_id
case selected do
[tag_name] ->
case Repo.get_by(Tag, project_id: project_id, name: tag_name) do
nil ->
socket
%Tag{} = tag ->
with {:ok, _updated_tag} <-
Tags.update_tag(tag.id, %{
color: blank_to_nil(Map.get(draft, "color")),
post_template_slug: blank_to_nil(Map.get(draft, "post_template_slug"))
}),
{:ok, renamed_tag} <- maybe_rename_tag(tag, Map.get(draft, "name", tag.name)) do
notify_parent(:tags_changed)
socket
|> put_in_tags_editor([:selected], [renamed_tag.name])
|> maybe_seed_edit_draft(project_id, [renamed_tag.name])
|> load_data()
else
{:error, reason} ->
notify_output(translated("Tags"), inspect(reason), "error")
socket
end
end
_other ->
socket
end
end
defp load_data(socket) do
project_id = socket.assigns.project_id
tags = tags =
Repo.all(from tag in Tag, where: tag.project_id == ^project_id, order_by: [asc: tag.name]) Repo.all(from tag in Tag, where: tag.project_id == ^project_id, order_by: [asc: tag.name])
counts = tag_counts(project_id) counts = tag_counts(project_id)
selected = Map.get(assigns, :tags_editor_selected, []) selected = Map.get(socket.assigns, :tags_editor, %{}) |> Map.get(:selected, [])
edit_tag = edit_tag =
if length(selected) == 1, do: Enum.find(tags, &(&1.name == hd(selected))), else: nil if length(selected) == 1, do: Enum.find(tags, &(&1.name == hd(selected))), else: nil
edit_draft = Map.get(assigns, :tags_editor_edit_draft, edit_draft(edit_tag)) edit_draft =
Map.get(socket.assigns, :tags_editor, %{}) |> Map.get(:edit_draft, edit_draft(edit_tag))
templates = templates =
Repo.all( Repo.all(
@@ -232,27 +264,39 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
select: %{slug: template.slug, title: template.title} select: %{slug: template.slug, title: template.title}
) )
selected_section = current_tags_section(assigns) selected_section = current_tags_section(socket.assigns)
%{ data = %{
tags: tags:
Enum.map(tags, fn tag -> Enum.map(tags, fn tag ->
%{name: tag.name, color: tag.color, count: Map.get(counts, tag.name, 0)} %{name: tag.name, color: tag.color, count: Map.get(counts, tag.name, 0)}
end), end),
selected: selected, selected: selected,
new_tag: Map.get(assigns, :tags_editor_new_tag, %{"name" => "", "color" => ""}), new_tag:
Map.get(socket.assigns, :tags_editor, %{}) |> Map.get(:new_tag, %{"name" => "", "color" => ""}),
edit_draft: edit_draft, edit_draft: edit_draft,
templates: templates, templates: templates,
merge_target: Map.get(assigns, :tags_editor_merge_target, List.first(selected) || ""), merge_target:
Map.get(socket.assigns, :tags_editor, %{}) |> Map.get(:merge_target, List.first(selected) || ""),
selected_section: selected_section selected_section: selected_section
} }
assign(socket, :tags_editor, data)
end end
def build(_assigns), do: nil defp put_in_tags_editor(socket, [key], value) do
assign(socket, :tags_editor, Map.put(socket.assigns.tags_editor, key, value))
end
@spec translated(term(), term()) :: term() defp noreply(socket), do: {:noreply, socket}
def translated(text, bindings \\ %{}),
do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current()) defp notify_parent(message) do
send(self(), message)
end
defp notify_output(title, message, level) do
send(self(), {:tags_editor_output, title, message, level})
end
@spec tag_font_size(term(), term()) :: term() @spec tag_font_size(term(), term()) :: term()
def tag_font_size(count, counts) do def tag_font_size(count, counts) do
@@ -274,14 +318,18 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
|> Enum.join("; ") |> Enum.join("; ")
end end
defp maybe_seed_edit_draft(socket, [tag_name]) do defp maybe_seed_edit_draft(socket, project_id, [tag_name]) do
case Repo.get_by(Tag, project_id: socket.assigns.projects.active_project_id, name: tag_name) do case Repo.get_by(Tag, project_id: project_id, name: tag_name) do
%Tag{} = tag -> assign(socket, :tags_editor_edit_draft, edit_draft(tag)) %Tag{} = tag ->
_other -> assign(socket, :tags_editor_edit_draft, %{}) put_in_tags_editor(socket, [:edit_draft], edit_draft(tag))
_other ->
put_in_tags_editor(socket, [:edit_draft], %{})
end end
end end
defp maybe_seed_edit_draft(socket, _selected), do: assign(socket, :tags_editor_edit_draft, %{}) defp maybe_seed_edit_draft(socket, _project_id, _selected),
do: put_in_tags_editor(socket, [:edit_draft], %{})
defp edit_draft(nil), do: %{} defp edit_draft(nil), do: %{}
@@ -314,13 +362,12 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
end end
end end
defp current_tab_meta(assigns) do defp current_tab_meta(%{current_tab: %{type: type, id: id}, tab_meta: tab_meta}) do
case Map.get(assigns, :current_tab) do Map.get(tab_meta || %{}, {type, id}, %{})
%{type: type, id: id} -> Map.get(assigns[:tab_meta] || %{}, {type, id}, %{})
_other -> %{}
end
end end
defp current_tab_meta(_assigns), do: %{}
defp tag_counts(project_id) do defp tag_counts(project_id) do
Repo.all(from post in Post, where: post.project_id == ^project_id, select: post.tags) Repo.all(from post in Post, where: post.project_id == ^project_id, select: post.tags)
|> List.flatten() |> List.flatten()
@@ -336,4 +383,7 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
trimmed -> trimmed trimmed -> trimmed
end end
end end
defp translated(text, bindings \\ %{}),
do: ShellData.translate(text, bindings, UILocale.current())
end end

View File

@@ -18,12 +18,12 @@
<%= if Enum.empty?(@tags_editor.tags) do %> <%= if Enum.empty?(@tags_editor.tags) do %>
<div class="tags-empty-state"> <div class="tags-empty-state">
<p><%= translated("No tags found") %></p> <p><%= translated("No tags found") %></p>
<button class="secondary" type="button" phx-click="sync_tags_editor"><%= translated("Discover") %></button> <button class="secondary" type="button" phx-click="sync_tags_editor" phx-target={@myself}><%= translated("Discover") %></button>
</div> </div>
<% else %> <% else %>
<div class="tag-cloud"> <div class="tag-cloud">
<%= for tag <- @tags_editor.tags do %> <%= 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}> <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} phx-target={@myself}>
<%= tag.name %><span class="tag-count"><%= tag.count %></span> <%= tag.name %><span class="tag-count"><%= tag.count %></span>
</button> </button>
<% end %> <% end %>
@@ -35,16 +35,16 @@
<div class="tags-section" id="tags-section-manage"> <div class="tags-section" id="tags-section-manage">
<div class="tags-section-header"><h3><%= translated("Create / Edit") %></h3></div> <div class="tags-section-header"><h3><%= translated("Create / Edit") %></h3></div>
<div class="tags-section-content"> <div class="tags-section-content">
<form class="tag-create-form" phx-change="change_new_tag_editor"> <form class="tag-create-form" phx-change="change_new_tag_editor" phx-target={@myself}>
<div class="tag-form-row"> <div class="tag-form-row">
<input type="text" name="new_tag[name]" value={@tags_editor.new_tag["name"]} placeholder={translated("Tag name")} /> <input type="text" name="new_tag[name]" value={@tags_editor.new_tag["name"]} placeholder={translated("Tag name")} />
<input type="color" name="new_tag[color]" value={if(@tags_editor.new_tag["color"] in [nil, ""], do: "#3b82f6", else: @tags_editor.new_tag["color"])} /> <input type="color" name="new_tag[color]" value={if(@tags_editor.new_tag["color"] in [nil, ""], do: "#3b82f6", else: @tags_editor.new_tag["color"])} />
<button class="primary" type="button" phx-click="create_tag_editor"><%= translated("Create") %></button> <button class="primary" type="button" phx-click="create_tag_editor" phx-target={@myself}><%= translated("Create") %></button>
</div> </div>
</form> </form>
<%= if @tags_editor.edit_draft != %{} do %> <%= if @tags_editor.edit_draft != %{} do %>
<form class="tag-edit-form" phx-change="change_edit_tag_editor"> <form class="tag-edit-form" phx-change="change_edit_tag_editor" phx-target={@myself}>
<div class="tag-form-row"> <div class="tag-form-row">
<input type="text" name="edit_tag[name]" value={@tags_editor.edit_draft["name"]} /> <input type="text" name="edit_tag[name]" value={@tags_editor.edit_draft["name"]} />
<input type="color" name="edit_tag[color]" value={if(@tags_editor.edit_draft["color"] in [nil, ""], do: "#3b82f6", else: @tags_editor.edit_draft["color"])} /> <input type="color" name="edit_tag[color]" value={if(@tags_editor.edit_draft["color"] in [nil, ""], do: "#3b82f6", else: @tags_editor.edit_draft["color"])} />
@@ -54,8 +54,8 @@
<option value={template.slug} selected={template.slug == @tags_editor.edit_draft["post_template_slug"]}><%= template.title %></option> <option value={template.slug} selected={template.slug == @tags_editor.edit_draft["post_template_slug"]}><%= template.title %></option>
<% end %> <% end %>
</select> </select>
<button class="primary" type="button" phx-click="save_tag_editor"><%= translated("Save") %></button> <button class="primary" type="button" phx-click="save_tag_editor" phx-target={@myself}><%= translated("Save") %></button>
<button class="danger" type="button" phx-click="delete_tag_editor"><%= translated("Delete") %></button> <button class="danger" type="button" phx-click="delete_tag_editor" phx-target={@myself}><%= translated("Delete") %></button>
</div> </div>
</form> </form>
<% end %> <% end %>
@@ -67,12 +67,12 @@
<div class="tags-section-content"> <div class="tags-section-content">
<div class="merge-form"> <div class="merge-form">
<div class="tag-form-row"> <div class="tag-form-row">
<select phx-change="change_merge_target" name="target"> <select phx-change="change_merge_target" name="target" phx-target={@myself}>
<%= for tag_name <- @tags_editor.selected do %> <%= for tag_name <- @tags_editor.selected do %>
<option value={tag_name} selected={tag_name == @tags_editor.merge_target}><%= tag_name %></option> <option value={tag_name} selected={tag_name == @tags_editor.merge_target}><%= tag_name %></option>
<% end %> <% end %>
</select> </select>
<button class="primary" type="button" phx-click="merge_tags_editor" disabled={length(@tags_editor.selected) < 2}><%= translated("Merge") %></button> <button class="primary" type="button" phx-click="merge_tags_editor" disabled={length(@tags_editor.selected) < 2} phx-target={@myself}><%= translated("Merge") %></button>
</div> </div>
</div> </div>
</div> </div>
@@ -81,7 +81,7 @@
<div class="tags-section" id="tags-section-sync"> <div class="tags-section" id="tags-section-sync">
<div class="tags-section-header"><h3><%= translated("Sync") %></h3></div> <div class="tags-section-header"><h3><%= translated("Sync") %></h3></div>
<div class="tags-section-content"> <div class="tags-section-content">
<button class="secondary" type="button" phx-click="sync_tags_editor"><%= translated("Discover") %></button> <button class="secondary" type="button" phx-click="sync_tags_editor" phx-target={@myself}><%= translated("Discover") %></button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -368,17 +368,34 @@ defmodule BDS.Desktop.ShellLiveTest do
|> element("[data-testid='sidebar-open-item'][data-item-id='tags-cloud']") |> element("[data-testid='sidebar-open-item'][data-item-id='tags-cloud']")
|> render_click() |> render_click()
html = render_click(view, "sync_tags_editor", %{}) html =
view
|> element("#tags-section-sync button[phx-click='sync_tags_editor']")
|> render_click()
assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha", "Beta"] assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha", "Beta"]
assert html =~ "Alpha" assert html =~ "Alpha"
assert html =~ "Beta" assert html =~ "Beta"
_html = render_click(view, "toggle_tag_selection", %{"name" => "Alpha"}) _html =
_html = render_click(view, "toggle_tag_selection", %{"name" => "Beta"}) view
_html = render_change(view, "change_merge_target", %{"target" => "Alpha"}) |> element("#tags-editor-shell button[phx-click='toggle_tag_selection'][phx-value-name='Alpha']")
|> render_click()
html = render_click(view, "merge_tags_editor", %{}) _html =
view
|> element("#tags-editor-shell button[phx-click='toggle_tag_selection'][phx-value-name='Beta']")
|> render_click()
_html =
view
|> element("#tags-editor-shell select[phx-change='change_merge_target']")
|> render_change(%{"target" => "Alpha"})
html =
view
|> element("#tags-editor-shell button[phx-click='merge_tags_editor']")
|> render_click()
assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha"] assert Enum.map(Tags.list_tags(project.id), & &1.name) == ["Alpha"]
assert Repo.get!(Post, post.id).tags == ["Alpha"] assert Repo.get!(Post, post.id).tags == ["Alpha"]