chore: switched MiscEditor to LiveComponent
This commit is contained in:
@@ -43,8 +43,7 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|
|
||||||
import TaskLocalization,
|
import TaskLocalization,
|
||||||
only: [
|
only: [
|
||||||
localize_task_status: 2,
|
localize_task_status: 2
|
||||||
translate_for_socket: 2
|
|
||||||
]
|
]
|
||||||
|
|
||||||
import TabHelpers,
|
import TabHelpers,
|
||||||
@@ -164,10 +163,6 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|> assign(:sidebar_filters_by_view, %{})
|
|> assign(:sidebar_filters_by_view, %{})
|
||||||
|> assign(:sidebar_filter_panels, %{})
|
|> assign(:sidebar_filter_panels, %{})
|
||||||
|> assign(:chat_editor_request_refs, %{})
|
|> assign(:chat_editor_request_refs, %{})
|
||||||
|> assign(:misc_editor_selected_pairs, %{})
|
|
||||||
|> assign(:misc_editor_git_selected_files, %{})
|
|
||||||
|> assign(:metadata_diff_active_tabs, %{})
|
|
||||||
|> assign(:metadata_diff_field_filters, %{})
|
|
||||||
|> assign(:shell_overlay, nil)
|
|> assign(:shell_overlay, nil)
|
||||||
|> assign(:output_entries, [])
|
|> assign(:output_entries, [])
|
||||||
|> reload_shell(workbench)}
|
|> reload_shell(workbench)}
|
||||||
@@ -315,133 +310,6 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
{:noreply, apply_shell_command(socket, action)}
|
{:noreply, apply_shell_command(socket, action)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("rerun_misc_editor", _params, socket) do
|
|
||||||
case MiscEditor.rerun(socket) do
|
|
||||||
{:command, action} -> {:noreply, apply_shell_command(socket, action)}
|
|
||||||
{:noop, next_socket} -> {:noreply, next_socket}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("apply_site_validation", _params, socket) do
|
|
||||||
case MiscEditor.apply_site_validation(socket, &append_output_entry/5) do
|
|
||||||
{:rerun, next_socket} -> {:noreply, apply_shell_command(next_socket, "validate_site")}
|
|
||||||
{:socket, next_socket} -> {:noreply, next_socket}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("fix_translation_validation", _params, socket) do
|
|
||||||
case MiscEditor.fix_translation_validation(socket, &append_output_entry/5) do
|
|
||||||
{:rerun, next_socket} ->
|
|
||||||
{:noreply, apply_shell_command(next_socket, "validate_translations")}
|
|
||||||
|
|
||||||
{:socket, next_socket} ->
|
|
||||||
{:noreply, next_socket}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("select_git_diff_file", %{"path" => path}, socket) do
|
|
||||||
{:noreply, socket |> MiscEditor.select_git_diff_file(path) |> assign_misc_editor()}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("toggle_duplicate_pair", %{"pair-id" => pair_id}, socket) do
|
|
||||||
{:noreply, MiscEditor.toggle_duplicate(socket, pair_id, &reload_shell/2)}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event(
|
|
||||||
"dismiss_duplicate_pair",
|
|
||||||
%{"post-id-a" => post_id_a, "post-id-b" => post_id_b},
|
|
||||||
socket
|
|
||||||
) do
|
|
||||||
{:noreply,
|
|
||||||
MiscEditor.dismiss_duplicate(
|
|
||||||
socket,
|
|
||||||
post_id_a,
|
|
||||||
post_id_b,
|
|
||||||
&reload_shell/2,
|
|
||||||
&append_output_entry/5
|
|
||||||
)}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("dismiss_selected_duplicates", _params, socket) do
|
|
||||||
{:noreply, MiscEditor.dismiss_selected(socket, &reload_shell/2, &append_output_entry/5)}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("repair_metadata_diff", %{"field" => field, "direction" => direction}, socket) do
|
|
||||||
case MiscEditor.metadata_diff_repair_request(socket, field, direction) do
|
|
||||||
{:ok, params} ->
|
|
||||||
{:noreply, apply_shell_command(socket, "repair_metadata_diff", params)}
|
|
||||||
|
|
||||||
{:error, message} ->
|
|
||||||
{:noreply,
|
|
||||||
append_output_entry(
|
|
||||||
socket,
|
|
||||||
translate_for_socket(socket, "Metadata Diff"),
|
|
||||||
message,
|
|
||||||
nil,
|
|
||||||
"error"
|
|
||||||
)}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("import_metadata_diff_orphans", _params, socket) do
|
|
||||||
case MiscEditor.metadata_diff_orphan_import_request(socket) do
|
|
||||||
{:ok, params} ->
|
|
||||||
{:noreply, apply_shell_command(socket, "import_metadata_diff_orphans", params)}
|
|
||||||
|
|
||||||
{:error, message} ->
|
|
||||||
{:noreply,
|
|
||||||
append_output_entry(
|
|
||||||
socket,
|
|
||||||
translate_for_socket(socket, "Metadata Diff"),
|
|
||||||
message,
|
|
||||||
nil,
|
|
||||||
"error"
|
|
||||||
)}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("select_metadata_diff_tab", %{"tab" => tab}, socket) do
|
|
||||||
tab_id = socket.assigns.current_tab.id
|
|
||||||
|
|
||||||
socket =
|
|
||||||
socket
|
|
||||||
|> assign(
|
|
||||||
:metadata_diff_active_tabs,
|
|
||||||
Map.put(socket.assigns.metadata_diff_active_tabs, tab_id, tab)
|
|
||||||
)
|
|
||||||
|> assign(
|
|
||||||
:metadata_diff_field_filters,
|
|
||||||
Map.delete(socket.assigns.metadata_diff_field_filters, tab_id)
|
|
||||||
)
|
|
||||||
|> assign_misc_editor()
|
|
||||||
|
|
||||||
{:noreply, socket}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("toggle_metadata_diff_field", %{"field" => field}, socket) do
|
|
||||||
tab_id = socket.assigns.current_tab.id
|
|
||||||
current = Map.get(socket.assigns.metadata_diff_field_filters, tab_id)
|
|
||||||
|
|
||||||
next_filters =
|
|
||||||
if current == field do
|
|
||||||
Map.delete(socket.assigns.metadata_diff_field_filters, tab_id)
|
|
||||||
else
|
|
||||||
Map.put(socket.assigns.metadata_diff_field_filters, tab_id, field)
|
|
||||||
end
|
|
||||||
|
|
||||||
{:noreply,
|
|
||||||
socket |> assign(:metadata_diff_field_filters, next_filters) |> assign_misc_editor()}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("open_duplicate_post", %{"id" => id, "title" => title}, socket) do
|
|
||||||
{:noreply,
|
|
||||||
open_sidebar_item(
|
|
||||||
socket,
|
|
||||||
%{"route" => "post", "id" => id, "title" => title, "subtitle" => "draft"},
|
|
||||||
:preview
|
|
||||||
)}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("open_overlay", %{"kind" => kind}, socket) do
|
def handle_event("open_overlay", %{"kind" => kind}, socket) do
|
||||||
socket =
|
socket =
|
||||||
case socket.assigns[:current_tab] do
|
case socket.assigns[:current_tab] do
|
||||||
@@ -1003,6 +871,21 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
{:noreply, append_output_entry(socket, title, message, nil, level)}
|
{:noreply, append_output_entry(socket, title, message, nil, level)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_info({:misc_editor_output, title, message, _detail, level}, socket) do
|
||||||
|
{:noreply, append_output_entry(socket, title, message, nil, level)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info({:misc_editor_command, action, params}, socket) do
|
||||||
|
{:noreply, apply_shell_command(socket, action, params)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info({:misc_editor_tab_meta, tab_type, tab_id, updates}, socket) do
|
||||||
|
key = {tab_type, tab_id}
|
||||||
|
current_meta = Map.get(socket.assigns.tab_meta, key, %{})
|
||||||
|
next_meta = Map.merge(current_meta, updates)
|
||||||
|
{:noreply, assign(socket, :tab_meta, Map.put(socket.assigns.tab_meta, key, next_meta))}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_info({:post_editor_output, title, message, level}, socket) do
|
def handle_info({:post_editor_output, title, message, level}, socket) do
|
||||||
{:noreply, append_output_entry(socket, title, message, nil, level)}
|
{:noreply, append_output_entry(socket, title, message, nil, level)}
|
||||||
end
|
end
|
||||||
@@ -1206,7 +1089,6 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
|> assign(:menu_groups, socket.assigns[:menu_groups] || TitlebarMenu.groups())
|
|> assign(:menu_groups, socket.assigns[:menu_groups] || TitlebarMenu.groups())
|
||||||
|> assign(:titlebar_menu_item_index, socket.assigns[:titlebar_menu_item_index])
|
|> assign(:titlebar_menu_item_index, socket.assigns[:titlebar_menu_item_index])
|
||||||
|> assign(:current_tab, current_tab(workbench))
|
|> assign(:current_tab, current_tab(workbench))
|
||||||
|> assign_misc_editor()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp translated(text, bindings \\ %{}),
|
defp translated(text, bindings \\ %{}),
|
||||||
@@ -1248,10 +1130,6 @@ defmodule BDS.Desktop.ShellLive do
|
|||||||
Enum.find(tabs, &(&1.type == type and &1.id == id))
|
Enum.find(tabs, &(&1.type == type and &1.id == id))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assign_misc_editor(socket) do
|
|
||||||
MiscEditor.assign_socket(socket)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp create_sidebar_item(socket, kind),
|
defp create_sidebar_item(socket, kind),
|
||||||
do: SidebarCreate.create(socket, kind, sidebar_create_callbacks())
|
do: SidebarCreate.create(socket, kind, sidebar_create_callbacks())
|
||||||
|
|
||||||
|
|||||||
@@ -421,8 +421,8 @@
|
|||||||
<% @current_tab.type == :import -> %>
|
<% @current_tab.type == :import -> %>
|
||||||
<.live_component module={ImportEditor} id={"import-editor-#{@current_tab.id}"} current_tab={@current_tab} offline_mode={@offline_mode} project_id={@projects.active_project_id} />
|
<.live_component module={ImportEditor} id={"import-editor-#{@current_tab.id}"} current_tab={@current_tab} offline_mode={@offline_mode} project_id={@projects.active_project_id} />
|
||||||
|
|
||||||
<% @current_tab.type in [:site_validation, :metadata_diff, :translation_validation, :find_duplicates, :git_diff] and @misc_editor -> %>
|
<% @current_tab.type in [:site_validation, :metadata_diff, :translation_validation, :find_duplicates, :git_diff] -> %>
|
||||||
<MiscEditor.misc_editor misc_editor={@misc_editor} />
|
<.live_component module={MiscEditor} id={"misc-editor-#{@current_tab.type}-#{@current_tab.id}"} current_tab={@current_tab} tab_meta={@tab_meta} project_id={@projects.active_project_id} />
|
||||||
|
|
||||||
<% true -> %>
|
<% true -> %>
|
||||||
<div class="editor-frame">
|
<div class="editor-frame">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
defmodule BDS.Desktop.ShellLive.MiscEditor do
|
defmodule BDS.Desktop.ShellLive.MiscEditor do
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
|
|
||||||
use Phoenix.Component
|
use Phoenix.LiveComponent
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@@ -20,30 +20,60 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
:git_diff
|
:git_diff
|
||||||
]
|
]
|
||||||
|
|
||||||
@spec assign_socket(term()) :: term()
|
# ── LiveComponent lifecycle ────────────────────────────────────────────────
|
||||||
def assign_socket(socket) do
|
|
||||||
assign(socket, :misc_editor, build(socket.assigns))
|
@spec update(map(), Phoenix.LiveView.Socket.t()) :: {:ok, Phoenix.LiveView.Socket.t()}
|
||||||
|
@impl true
|
||||||
|
def update(%{current_tab: current_tab, tab_meta: tab_meta, project_id: project_id}, socket) do
|
||||||
|
socket =
|
||||||
|
socket
|
||||||
|
|> assign(:current_tab, current_tab)
|
||||||
|
|> assign(:project_id, project_id)
|
||||||
|
|> assign(:tab_meta, tab_meta)
|
||||||
|
|> ensure_state()
|
||||||
|
|> build_data()
|
||||||
|
|
||||||
|
{:ok, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec rerun(term()) :: term()
|
defp ensure_state(socket) do
|
||||||
def rerun(socket) do
|
socket
|
||||||
case meta(socket.assigns) do
|
|> assign_new(:selected_pairs, fn -> MapSet.new() end)
|
||||||
%{action: action} when is_binary(action) ->
|
|> assign_new(:git_selected_file, fn -> nil end)
|
||||||
{:command, action}
|
|> assign_new(:active_tab, fn -> nil end)
|
||||||
|
|> assign_new(:active_field, fn -> nil end)
|
||||||
_other ->
|
|
||||||
case misc_route_action(socket.assigns.current_tab.type) do
|
|
||||||
nil -> {:noop, socket}
|
|
||||||
action -> {:command, action}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec apply_site_validation(term(), term()) :: term()
|
defp build_data(socket) do
|
||||||
def apply_site_validation(socket, append_output) do
|
misc_editor = do_build(socket.assigns)
|
||||||
|
assign(socket, :misc_editor, misc_editor)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec render(map()) :: Phoenix.LiveView.Rendered.t()
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
misc_editor(assigns)
|
||||||
|
end
|
||||||
|
|
||||||
|
# ── Event handlers ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@spec handle_event(String.t(), map(), Phoenix.LiveView.Socket.t()) ::
|
||||||
|
{:noreply, Phoenix.LiveView.Socket.t()}
|
||||||
|
@impl true
|
||||||
|
def handle_event("rerun_misc_editor", _params, socket) do
|
||||||
|
action = rerun_action(socket.assigns)
|
||||||
|
|
||||||
|
if action do
|
||||||
|
notify_command(action)
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("apply_site_validation", _params, socket) do
|
||||||
meta = meta(socket.assigns)
|
meta = meta(socket.assigns)
|
||||||
payload = Map.get(meta, :payload, %{})
|
payload = Map.get(meta, :payload, %{})
|
||||||
project_id = Map.get(meta, :project_id, socket.assigns.projects.active_project_id)
|
project_id = Map.get(meta, :project_id, socket.assigns.project_id)
|
||||||
|
|
||||||
report = %{
|
report = %{
|
||||||
sitemap_path: Map.get(payload, :sitemap_path),
|
sitemap_path: Map.get(payload, :sitemap_path),
|
||||||
@@ -57,98 +87,17 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
|
|
||||||
case Generation.apply_validation(project_id, report) do
|
case Generation.apply_validation(project_id, report) do
|
||||||
{:ok, result} ->
|
{:ok, result} ->
|
||||||
{:rerun,
|
notify_output(translated("Site Validation"), translated("Validation changes applied"), inspect(result))
|
||||||
socket
|
notify_command("validate_site")
|
||||||
|> append_output.(
|
{:noreply, socket}
|
||||||
translated("Site Validation"),
|
|
||||||
translated("Validation changes applied"),
|
|
||||||
inspect(result)
|
|
||||||
)}
|
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
error ->
|
error ->
|
||||||
{:socket,
|
notify_output(translated("Site Validation"), inspect(error), nil, "error")
|
||||||
append_output.(socket, translated("Site Validation"), inspect(error), nil, "error")}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec toggle_duplicate(term(), term(), term()) :: term()
|
def handle_event("fix_translation_validation", _params, socket) do
|
||||||
def toggle_duplicate(socket, pair_id, reload) do
|
|
||||||
selected_by_tab = Map.get(socket.assigns, :misc_editor_selected_pairs, %{})
|
|
||||||
current = Map.get(selected_by_tab, socket.assigns.current_tab.id, MapSet.new())
|
|
||||||
|
|
||||||
next =
|
|
||||||
if MapSet.member?(current, pair_id) do
|
|
||||||
MapSet.delete(current, pair_id)
|
|
||||||
else
|
|
||||||
MapSet.put(current, pair_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
socket
|
|
||||||
|> assign(
|
|
||||||
:misc_editor_selected_pairs,
|
|
||||||
Map.put(selected_by_tab, socket.assigns.current_tab.id, next)
|
|
||||||
)
|
|
||||||
|> reload.(socket.assigns.workbench)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec dismiss_duplicate(term(), term(), term(), term(), term()) :: term()
|
|
||||||
def dismiss_duplicate(socket, post_id_a, post_id_b, reload, append_output) do
|
|
||||||
case Embeddings.dismiss_duplicate_pair(post_id_a, post_id_b) do
|
|
||||||
{:ok, _saved_pair} ->
|
|
||||||
socket
|
|
||||||
|> update_payload(fn payload ->
|
|
||||||
update_in(payload[:pairs], fn pairs ->
|
|
||||||
Enum.reject(pairs || [], fn pair ->
|
|
||||||
pair_identity(pair) == pair_id(post_id_a, post_id_b)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|> clear_selected_pair(pair_id(post_id_a, post_id_b))
|
|
||||||
|> append_output.(translated("Find Duplicates"), translated("Pair dismissed"))
|
|
||||||
|> reload.(socket.assigns.workbench)
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
socket
|
|
||||||
|> append_output.(translated("Find Duplicates"), inspect(reason), nil, "error")
|
|
||||||
|> reload.(socket.assigns.workbench)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec dismiss_selected(term(), term(), term()) :: term()
|
|
||||||
def dismiss_selected(socket, reload, append_output) do
|
|
||||||
tab_id = socket.assigns.current_tab.id
|
|
||||||
|
|
||||||
selected =
|
|
||||||
socket.assigns.misc_editor_selected_pairs
|
|
||||||
|> Map.get(tab_id, MapSet.new())
|
|
||||||
|> MapSet.to_list()
|
|
||||||
|> Enum.map(&decode_pair_id/1)
|
|
||||||
|> Enum.reject(&is_nil/1)
|
|
||||||
|
|
||||||
case Embeddings.dismiss_duplicate_pairs(selected) do
|
|
||||||
{:ok, _saved_pairs} ->
|
|
||||||
socket
|
|
||||||
|> update_payload(fn payload ->
|
|
||||||
update_in(payload[:pairs], fn pairs ->
|
|
||||||
Enum.reject(pairs || [], fn pair -> pair_identity(pair) in selected end)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|> assign(
|
|
||||||
:misc_editor_selected_pairs,
|
|
||||||
Map.put(socket.assigns.misc_editor_selected_pairs, tab_id, MapSet.new())
|
|
||||||
)
|
|
||||||
|> append_output.(translated("Find Duplicates"), translated("Selected pairs dismissed"))
|
|
||||||
|> reload.(socket.assigns.workbench)
|
|
||||||
|
|
||||||
{:error, reason} ->
|
|
||||||
socket
|
|
||||||
|> append_output.(translated("Find Duplicates"), inspect(reason), nil, "error")
|
|
||||||
|> reload.(socket.assigns.workbench)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec fix_translation_validation(term(), term()) :: term()
|
|
||||||
def fix_translation_validation(socket, append_output) do
|
|
||||||
report =
|
report =
|
||||||
socket.assigns
|
socket.assigns
|
||||||
|> meta()
|
|> meta()
|
||||||
@@ -157,93 +106,254 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
|
|
||||||
{:ok, result} = Posts.fix_invalid_translations(report)
|
{:ok, result} = Posts.fix_invalid_translations(report)
|
||||||
|
|
||||||
{:rerun,
|
notify_output(
|
||||||
socket
|
|
||||||
|> append_output.(
|
|
||||||
translated("Translation Validation"),
|
translated("Translation Validation"),
|
||||||
translated("translationValidation.toast.fixSuccess", %{
|
translated("translationValidation.toast.fixSuccess", %{
|
||||||
dbRows: result.deleted_database_rows,
|
dbRows: result.deleted_database_rows,
|
||||||
files: result.deleted_files,
|
files: result.deleted_files,
|
||||||
flushed: result.flushed_translations
|
flushed: result.flushed_translations
|
||||||
})
|
})
|
||||||
)}
|
)
|
||||||
|
|
||||||
|
notify_command("validate_translations")
|
||||||
|
{:noreply, socket}
|
||||||
rescue
|
rescue
|
||||||
error ->
|
error ->
|
||||||
{:socket,
|
notify_output(translated("Translation Validation"), inspect(error), nil, "error")
|
||||||
append_output.(socket, translated("Translation Validation"), inspect(error), nil, "error")}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec select_git_diff_file(term(), term()) :: term()
|
def handle_event("select_git_diff_file", %{"path" => path}, socket) do
|
||||||
def select_git_diff_file(socket, file_path) do
|
{:noreply, assign(socket, :git_selected_file, path) |> build_data()}
|
||||||
assign(
|
|
||||||
socket,
|
|
||||||
:misc_editor_git_selected_files,
|
|
||||||
Map.put(
|
|
||||||
socket.assigns.misc_editor_git_selected_files,
|
|
||||||
socket.assigns.current_tab.id,
|
|
||||||
file_path
|
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec metadata_diff_repair_request(term(), term(), term()) :: term()
|
def handle_event("toggle_duplicate_pair", %{"pair-id" => pair_id}, socket) do
|
||||||
def metadata_diff_repair_request(socket, field, direction) do
|
current = socket.assigns.selected_pairs
|
||||||
meta = meta(socket.assigns)
|
|
||||||
payload = Map.get(meta, :payload, %{})
|
|
||||||
items = Enum.map(Map.get(payload, :diff_reports, []), &normalize_metadata_diff_item/1)
|
|
||||||
tabs = metadata_diff_tabs(items, [])
|
|
||||||
active_tab = metadata_diff_active_tab(socket.assigns, tabs)
|
|
||||||
|
|
||||||
repair_items =
|
next =
|
||||||
items
|
if MapSet.member?(current, pair_id) do
|
||||||
|> Enum.filter(&(&1.tab_id == active_tab))
|
MapSet.delete(current, pair_id)
|
||||||
|> Enum.filter(fn item -> Enum.any?(item.differences, &(diff_name(&1) == field)) end)
|
|
||||||
|> Enum.map(&%{"entity_type" => &1.entity_type, "entity_id" => &1.entity_id})
|
|
||||||
|
|
||||||
cond do
|
|
||||||
not metadata_diff_repairable_tab?(active_tab) ->
|
|
||||||
{:error, translated("No repair action available")}
|
|
||||||
|
|
||||||
repair_items == [] ->
|
|
||||||
{:error, translated("No metadata diff items selected")}
|
|
||||||
|
|
||||||
true ->
|
|
||||||
{:ok,
|
|
||||||
%{
|
|
||||||
"direction" => direction,
|
|
||||||
"field" => field,
|
|
||||||
"tab" => active_tab,
|
|
||||||
"items" => repair_items
|
|
||||||
}}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec metadata_diff_orphan_import_request(term()) :: term()
|
|
||||||
def metadata_diff_orphan_import_request(socket) do
|
|
||||||
meta = meta(socket.assigns)
|
|
||||||
payload = Map.get(meta, :payload, %{})
|
|
||||||
items = Enum.map(Map.get(payload, :diff_reports, []), &normalize_metadata_diff_item/1)
|
|
||||||
|
|
||||||
orphan_files =
|
|
||||||
Enum.map(Map.get(payload, :orphan_reports, []), &normalize_metadata_diff_orphan/1)
|
|
||||||
|
|
||||||
tabs = metadata_diff_tabs(items, orphan_files)
|
|
||||||
active_tab = metadata_diff_active_tab(socket.assigns, tabs)
|
|
||||||
|
|
||||||
selected_orphans =
|
|
||||||
orphan_files
|
|
||||||
|> Enum.filter(&(&1.tab_id == active_tab))
|
|
||||||
|> Enum.map(&%{"file_path" => &1.file_path})
|
|
||||||
|
|
||||||
if selected_orphans == [] do
|
|
||||||
{:error, translated("No orphan files selected")}
|
|
||||||
else
|
else
|
||||||
{:ok, %{"tab" => active_tab, "orphans" => selected_orphans}}
|
MapSet.put(current, pair_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, assign(socket, :selected_pairs, next) |> build_data()}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event(
|
||||||
|
"dismiss_duplicate_pair",
|
||||||
|
%{"post-id-a" => post_id_a, "post-id-b" => post_id_b},
|
||||||
|
socket
|
||||||
|
) do
|
||||||
|
case Embeddings.dismiss_duplicate_pair(post_id_a, post_id_b) do
|
||||||
|
{:ok, _saved_pair} ->
|
||||||
|
tab_type = socket.assigns.current_tab.type
|
||||||
|
tab_id = socket.assigns.current_tab.id
|
||||||
|
pair_id = pair_id(post_id_a, post_id_b)
|
||||||
|
|
||||||
|
payload = Map.get(meta(socket.assigns), :payload, %{})
|
||||||
|
|
||||||
|
next_pairs =
|
||||||
|
update_in(payload[:pairs], fn pairs ->
|
||||||
|
Enum.reject(pairs || [], fn pair ->
|
||||||
|
pair_identity(pair) == pair_id
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
next_payload = Map.put(payload, :pairs, next_pairs)
|
||||||
|
notify_tab_meta(tab_type, tab_id, %{payload: next_payload})
|
||||||
|
notify_output(translated("Find Duplicates"), translated("Pair dismissed"))
|
||||||
|
|
||||||
|
selected = MapSet.delete(socket.assigns.selected_pairs, pair_id)
|
||||||
|
{:noreply, assign(socket, :selected_pairs, selected) |> build_data()}
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
|
notify_output(translated("Find Duplicates"), inspect(reason), nil, "error")
|
||||||
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec build(term()) :: term()
|
def handle_event("dismiss_selected_duplicates", _params, socket) do
|
||||||
def build(%{current_tab: %{type: type}} = assigns) when type in @misc_routes do
|
selected =
|
||||||
|
socket.assigns.selected_pairs
|
||||||
|
|> MapSet.to_list()
|
||||||
|
|> Enum.map(&decode_pair_id/1)
|
||||||
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|
||||||
|
case Embeddings.dismiss_duplicate_pairs(selected) do
|
||||||
|
{:ok, _saved_pairs} ->
|
||||||
|
tab_type = socket.assigns.current_tab.type
|
||||||
|
tab_id = socket.assigns.current_tab.id
|
||||||
|
payload = Map.get(meta(socket.assigns), :payload, %{})
|
||||||
|
|
||||||
|
next_pairs =
|
||||||
|
update_in(payload[:pairs], fn pairs ->
|
||||||
|
Enum.reject(pairs || [], fn pair -> pair_identity(pair) in selected end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
next_payload = Map.put(payload, :pairs, next_pairs)
|
||||||
|
notify_tab_meta(tab_type, tab_id, %{payload: next_payload})
|
||||||
|
notify_output(translated("Find Duplicates"), translated("Selected pairs dismissed"))
|
||||||
|
|
||||||
|
{:noreply, assign(socket, :selected_pairs, MapSet.new()) |> build_data()}
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
|
notify_output(translated("Find Duplicates"), inspect(reason), nil, "error")
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("repair_metadata_diff", %{"field" => field, "direction" => direction}, socket) do
|
||||||
|
case metadata_diff_repair_request(socket.assigns, field, direction) do
|
||||||
|
{:ok, params} ->
|
||||||
|
notify_command("repair_metadata_diff", params)
|
||||||
|
{:noreply, socket}
|
||||||
|
|
||||||
|
{:error, message} ->
|
||||||
|
notify_output(translated("Metadata Diff"), message, nil, "error")
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("import_metadata_diff_orphans", _params, socket) do
|
||||||
|
case metadata_diff_orphan_import_request(socket.assigns) do
|
||||||
|
{:ok, params} ->
|
||||||
|
notify_command("import_metadata_diff_orphans", params)
|
||||||
|
{:noreply, socket}
|
||||||
|
|
||||||
|
{:error, message} ->
|
||||||
|
notify_output(translated("Metadata Diff"), message, nil, "error")
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("select_metadata_diff_tab", %{"tab" => tab}, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> assign(:active_tab, tab)
|
||||||
|
|> assign(:active_field, nil)
|
||||||
|
|> build_data()}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("toggle_metadata_diff_field", %{"field" => field}, socket) do
|
||||||
|
current = socket.assigns.active_field
|
||||||
|
next = if current == field, do: nil, else: field
|
||||||
|
{:noreply, assign(socket, :active_field, next) |> build_data()}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("open_duplicate_post", %{"id" => id, "title" => title}, socket) do
|
||||||
|
notify_open_sidebar_item(%{"route" => "post", "id" => id, "title" => title, "subtitle" => "draft"}, :preview)
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
# ── Public helper functions (used by template) ─────────────────────────────
|
||||||
|
|
||||||
|
@spec translated(String.t(), map()) :: String.t()
|
||||||
|
def translated(text, bindings \\ %{}),
|
||||||
|
do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current())
|
||||||
|
|
||||||
|
@spec misc_class(atom()) :: String.t()
|
||||||
|
def misc_class(:site_validation), do: "site-validation-view"
|
||||||
|
def misc_class(:metadata_diff), do: "metadata-diff-view"
|
||||||
|
def misc_class(:translation_validation), do: "translation-validation-view"
|
||||||
|
def misc_class(:find_duplicates), do: "duplicates-view"
|
||||||
|
def misc_class(:git_diff), do: "git-diff-view"
|
||||||
|
|
||||||
|
@spec summary_items(map()) :: [{String.t(), any()}]
|
||||||
|
def summary_items(%{summary: summary}) when is_map(summary), do: Enum.to_list(summary)
|
||||||
|
def summary_items(_misc), do: []
|
||||||
|
|
||||||
|
@spec duplicate_checked?(map(), String.t()) :: boolean()
|
||||||
|
def duplicate_checked?(misc, pair_id), do: MapSet.member?(misc.selected_pairs, pair_id)
|
||||||
|
|
||||||
|
@spec pair_id_from_pair(map()) :: String.t()
|
||||||
|
def pair_id_from_pair(pair), do: pair_identity(pair)
|
||||||
|
|
||||||
|
@spec translation_issue_label(map()) :: String.t()
|
||||||
|
def translation_issue_label(issue) do
|
||||||
|
case issue_value(issue, :issue) do
|
||||||
|
"same-language-as-canonical" ->
|
||||||
|
translated("translationValidation.issue.sameLanguage")
|
||||||
|
|
||||||
|
"do-not-translate-has-translations" ->
|
||||||
|
translated("translationValidation.issue.doNotTranslate")
|
||||||
|
|
||||||
|
"content-in-database" ->
|
||||||
|
translated("translationValidation.issue.contentInDatabase")
|
||||||
|
|
||||||
|
_other ->
|
||||||
|
translated("translationValidation.issue.missingSource")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec translation_issue_languages(map()) :: String.t()
|
||||||
|
def translation_issue_languages(issue) do
|
||||||
|
canonical_language = issue_value(issue, :canonical_language)
|
||||||
|
translation_language = issue_value(issue, :translation_language)
|
||||||
|
|
||||||
|
if canonical_language in [nil, ""] do
|
||||||
|
translation_language
|
||||||
|
else
|
||||||
|
translated("translationValidation.languagesWithCanonical", %{
|
||||||
|
canonical: canonical_language,
|
||||||
|
translation: translation_language
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec translation_issue_value(map(), atom() | String.t()) :: any()
|
||||||
|
def translation_issue_value(issue, key), do: issue_value(issue, key)
|
||||||
|
|
||||||
|
@spec git_diff_language(String.t() | nil) :: String.t()
|
||||||
|
def git_diff_language(nil), do: "plaintext"
|
||||||
|
|
||||||
|
def git_diff_language(file_path) do
|
||||||
|
case file_path |> Path.extname() |> String.downcase() do
|
||||||
|
".md" -> "markdown"
|
||||||
|
".markdown" -> "markdown"
|
||||||
|
".mdx" -> "markdown"
|
||||||
|
".ts" -> "typescript"
|
||||||
|
".tsx" -> "typescript"
|
||||||
|
".js" -> "javascript"
|
||||||
|
".jsx" -> "javascript"
|
||||||
|
".json" -> "json"
|
||||||
|
".css" -> "css"
|
||||||
|
".html" -> "html"
|
||||||
|
".yml" -> "yaml"
|
||||||
|
".yaml" -> "yaml"
|
||||||
|
_other -> "plaintext"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ── Private helpers ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
defp notify_command(action, params \\ %{}) do
|
||||||
|
send(self(), {:misc_editor_command, action, params})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_output(title, message, detail \\ nil, level \\ "info") do
|
||||||
|
send(self(), {:misc_editor_output, title, message, detail, level})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_tab_meta(tab_type, tab_id, updates) do
|
||||||
|
send(self(), {:misc_editor_tab_meta, tab_type, tab_id, updates})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp notify_open_sidebar_item(params, intent) do
|
||||||
|
send(self(), {:open_sidebar_item, params, intent})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp rerun_action(assigns) do
|
||||||
|
case meta(assigns) do
|
||||||
|
%{action: action} when is_binary(action) ->
|
||||||
|
action
|
||||||
|
|
||||||
|
_other ->
|
||||||
|
misc_route_action(assigns.current_tab.type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp do_build(%{current_tab: %{type: type}} = assigns) when type in @misc_routes do
|
||||||
meta = meta(assigns)
|
meta = meta(assigns)
|
||||||
payload = Map.get(meta, :payload, %{})
|
payload = Map.get(meta, :payload, %{})
|
||||||
|
|
||||||
@@ -256,29 +366,7 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec build(term()) :: term()
|
defp do_build(_assigns), do: nil
|
||||||
def build(_assigns), do: nil
|
|
||||||
|
|
||||||
@spec translated(term(), term()) :: term()
|
|
||||||
def translated(text, bindings \\ %{}),
|
|
||||||
do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current())
|
|
||||||
|
|
||||||
@spec misc_class(term()) :: term()
|
|
||||||
def misc_class(:site_validation), do: "site-validation-view"
|
|
||||||
def misc_class(:metadata_diff), do: "metadata-diff-view"
|
|
||||||
def misc_class(:translation_validation), do: "translation-validation-view"
|
|
||||||
def misc_class(:find_duplicates), do: "duplicates-view"
|
|
||||||
def misc_class(:git_diff), do: "git-diff-view"
|
|
||||||
|
|
||||||
def summary_items(%{summary: summary}) when is_map(summary), do: Enum.to_list(summary)
|
|
||||||
@spec summary_items(term()) :: term()
|
|
||||||
def summary_items(_misc), do: []
|
|
||||||
|
|
||||||
@spec duplicate_checked?(term(), term()) :: term()
|
|
||||||
def duplicate_checked?(misc, pair_id), do: MapSet.member?(misc.selected_pairs, pair_id)
|
|
||||||
|
|
||||||
@spec pair_id_from_pair(term()) :: term()
|
|
||||||
def pair_id_from_pair(pair), do: pair_identity(pair)
|
|
||||||
|
|
||||||
defp build_site_validation(meta, payload) do
|
defp build_site_validation(meta, payload) do
|
||||||
summary = Map.get(payload, :summary, %{})
|
summary = Map.get(payload, :summary, %{})
|
||||||
@@ -311,8 +399,8 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
Enum.map(Map.get(payload, :orphan_reports, []), &normalize_metadata_diff_orphan/1)
|
Enum.map(Map.get(payload, :orphan_reports, []), &normalize_metadata_diff_orphan/1)
|
||||||
|
|
||||||
tabs = metadata_diff_tabs(items, orphan_files)
|
tabs = metadata_diff_tabs(items, orphan_files)
|
||||||
active_tab = metadata_diff_active_tab(assigns, tabs)
|
active_tab = assigns.active_tab || metadata_diff_active_tab_fallback(tabs)
|
||||||
active_field = metadata_diff_active_field(assigns)
|
active_field = assigns.active_field
|
||||||
|
|
||||||
current_tab =
|
current_tab =
|
||||||
Enum.find(tabs, &(&1.id == active_tab)) || List.first(tabs) || empty_metadata_diff_tab()
|
Enum.find(tabs, &(&1.id == active_tab)) || List.first(tabs) || empty_metadata_diff_tab()
|
||||||
@@ -358,22 +446,19 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp build_duplicates(assigns, meta, payload) do
|
defp build_duplicates(assigns, meta, payload) do
|
||||||
selected_pairs =
|
|
||||||
Map.get(assigns.misc_editor_selected_pairs, assigns.current_tab.id, MapSet.new())
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
kind: :find_duplicates,
|
kind: :find_duplicates,
|
||||||
title: Map.get(meta, :title, translated("Find Duplicates")),
|
title: Map.get(meta, :title, translated("Find Duplicates")),
|
||||||
subtitle: Map.get(meta, :subtitle, ""),
|
subtitle: Map.get(meta, :subtitle, ""),
|
||||||
summary: Map.get(payload, :summary, %{}),
|
summary: Map.get(payload, :summary, %{}),
|
||||||
pairs: Map.get(payload, :pairs, []),
|
pairs: Map.get(payload, :pairs, []),
|
||||||
selected_pairs: selected_pairs
|
selected_pairs: assigns.selected_pairs
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_git_diff(assigns, meta) do
|
defp build_git_diff(assigns, meta) do
|
||||||
project_id = assigns.projects.active_project_id
|
project_id = assigns.project_id
|
||||||
selected_files = Map.get(assigns, :misc_editor_git_selected_files, %{})
|
selected_file = assigns.git_selected_file
|
||||||
|
|
||||||
{files, diff, error_message} =
|
{files, diff, error_message} =
|
||||||
case Git.status(project_id) do
|
case Git.status(project_id) do
|
||||||
@@ -386,7 +471,11 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
|> Enum.sort()
|
|> Enum.sort()
|
||||||
|
|
||||||
selected_file_path =
|
selected_file_path =
|
||||||
select_git_diff_path(assigns.current_tab.id, file_paths, selected_files)
|
if selected_file in file_paths do
|
||||||
|
selected_file
|
||||||
|
else
|
||||||
|
List.first(file_paths)
|
||||||
|
end
|
||||||
|
|
||||||
diff =
|
diff =
|
||||||
case selected_file_path do
|
case selected_file_path do
|
||||||
@@ -427,81 +516,60 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec translation_issue_label(term()) :: term()
|
|
||||||
def translation_issue_label(issue) do
|
|
||||||
case issue_value(issue, :issue) do
|
|
||||||
"same-language-as-canonical" ->
|
|
||||||
translated("translationValidation.issue.sameLanguage")
|
|
||||||
|
|
||||||
"do-not-translate-has-translations" ->
|
|
||||||
translated("translationValidation.issue.doNotTranslate")
|
|
||||||
|
|
||||||
"content-in-database" ->
|
|
||||||
translated("translationValidation.issue.contentInDatabase")
|
|
||||||
|
|
||||||
_other ->
|
|
||||||
translated("translationValidation.issue.missingSource")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec translation_issue_languages(term()) :: term()
|
|
||||||
def translation_issue_languages(issue) do
|
|
||||||
canonical_language = issue_value(issue, :canonical_language)
|
|
||||||
translation_language = issue_value(issue, :translation_language)
|
|
||||||
|
|
||||||
if canonical_language in [nil, ""] do
|
|
||||||
translation_language
|
|
||||||
else
|
|
||||||
translated("translationValidation.languagesWithCanonical", %{
|
|
||||||
canonical: canonical_language,
|
|
||||||
translation: translation_language
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec translation_issue_value(term(), term()) :: term()
|
|
||||||
def translation_issue_value(issue, key), do: issue_value(issue, key)
|
|
||||||
|
|
||||||
@spec git_diff_language(term()) :: term()
|
|
||||||
def git_diff_language(nil), do: "plaintext"
|
|
||||||
|
|
||||||
def git_diff_language(file_path) do
|
|
||||||
case file_path |> Path.extname() |> String.downcase() do
|
|
||||||
".md" -> "markdown"
|
|
||||||
".markdown" -> "markdown"
|
|
||||||
".mdx" -> "markdown"
|
|
||||||
".ts" -> "typescript"
|
|
||||||
".tsx" -> "typescript"
|
|
||||||
".js" -> "javascript"
|
|
||||||
".jsx" -> "javascript"
|
|
||||||
".json" -> "json"
|
|
||||||
".css" -> "css"
|
|
||||||
".html" -> "html"
|
|
||||||
".yml" -> "yaml"
|
|
||||||
".yaml" -> "yaml"
|
|
||||||
_other -> "plaintext"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp meta(assigns) do
|
defp meta(assigns) do
|
||||||
Map.get(assigns.tab_meta, {assigns.current_tab.type, assigns.current_tab.id}, %{})
|
Map.get(assigns.tab_meta, {assigns.current_tab.type, assigns.current_tab.id}, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp update_payload(socket, updater) do
|
defp metadata_diff_repair_request(assigns, field, direction) do
|
||||||
key = {socket.assigns.current_tab.type, socket.assigns.current_tab.id}
|
payload = Map.get(meta(assigns), :payload, %{})
|
||||||
meta = Map.get(socket.assigns.tab_meta, key, %{})
|
items = Enum.map(Map.get(payload, :diff_reports, []), &normalize_metadata_diff_item/1)
|
||||||
next_meta = Map.update(meta, :payload, %{}, updater)
|
tabs = metadata_diff_tabs(items, [])
|
||||||
assign(socket, :tab_meta, Map.put(socket.assigns.tab_meta, key, next_meta))
|
active_tab = assigns.active_tab || metadata_diff_active_tab_fallback(tabs)
|
||||||
|
|
||||||
|
repair_items =
|
||||||
|
items
|
||||||
|
|> Enum.filter(&(&1.tab_id == active_tab))
|
||||||
|
|> Enum.filter(fn item -> Enum.any?(item.differences, &(diff_name(&1) == field)) end)
|
||||||
|
|> Enum.map(&%{"entity_type" => &1.entity_type, "entity_id" => &1.entity_id})
|
||||||
|
|
||||||
|
cond do
|
||||||
|
not metadata_diff_repairable_tab?(active_tab) ->
|
||||||
|
{:error, translated("No repair action available")}
|
||||||
|
|
||||||
|
repair_items == [] ->
|
||||||
|
{:error, translated("No metadata diff items selected")}
|
||||||
|
|
||||||
|
true ->
|
||||||
|
{:ok,
|
||||||
|
%{
|
||||||
|
"direction" => direction,
|
||||||
|
"field" => field,
|
||||||
|
"tab" => active_tab,
|
||||||
|
"items" => repair_items
|
||||||
|
}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp clear_selected_pair(socket, pair_id) do
|
defp metadata_diff_orphan_import_request(assigns) do
|
||||||
tab_id = socket.assigns.current_tab.id
|
payload = Map.get(meta(assigns), :payload, %{})
|
||||||
current = Map.get(socket.assigns.misc_editor_selected_pairs, tab_id, MapSet.new())
|
items = Enum.map(Map.get(payload, :diff_reports, []), &normalize_metadata_diff_item/1)
|
||||||
|
|
||||||
next_pairs =
|
orphan_files =
|
||||||
Map.put(socket.assigns.misc_editor_selected_pairs, tab_id, MapSet.delete(current, pair_id))
|
Enum.map(Map.get(payload, :orphan_reports, []), &normalize_metadata_diff_orphan/1)
|
||||||
|
|
||||||
assign(socket, :misc_editor_selected_pairs, next_pairs)
|
tabs = metadata_diff_tabs(items, orphan_files)
|
||||||
|
active_tab = assigns.active_tab || metadata_diff_active_tab_fallback(tabs)
|
||||||
|
|
||||||
|
selected_orphans =
|
||||||
|
orphan_files
|
||||||
|
|> Enum.filter(&(&1.tab_id == active_tab))
|
||||||
|
|> Enum.map(&%{"file_path" => &1.file_path})
|
||||||
|
|
||||||
|
if selected_orphans == [] do
|
||||||
|
{:error, translated("No orphan files selected")}
|
||||||
|
else
|
||||||
|
{:ok, %{"tab" => active_tab, "orphans" => selected_orphans}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp pair_id(post_id_a, post_id_b), do: Enum.sort([post_id_a, post_id_b]) |> Enum.join("::")
|
defp pair_id(post_id_a, post_id_b), do: Enum.sort([post_id_a, post_id_b]) |> Enum.join("::")
|
||||||
@@ -564,19 +632,9 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp metadata_diff_active_tab(assigns, tabs) do
|
defp metadata_diff_active_tab_fallback(tabs) do
|
||||||
tab_id = Map.get(assigns.metadata_diff_active_tabs || %{}, assigns.current_tab.id)
|
|
||||||
|
|
||||||
if Enum.any?(tabs, &(&1.id == tab_id)) do
|
|
||||||
tab_id
|
|
||||||
else
|
|
||||||
tabs |> List.first() |> Map.get(:id)
|
tabs |> List.first() |> Map.get(:id)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
defp metadata_diff_active_field(assigns) do
|
|
||||||
Map.get(assigns.metadata_diff_field_filters || %{}, assigns.current_tab.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp metadata_diff_filtered_items(items, nil), do: items
|
defp metadata_diff_filtered_items(items, nil), do: items
|
||||||
|
|
||||||
@@ -737,16 +795,6 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do
|
|||||||
|
|
||||||
defp issue_value(_issue, _key), do: nil
|
defp issue_value(_issue, _key), do: nil
|
||||||
|
|
||||||
defp select_git_diff_path(tab_id, files, selected_files) do
|
|
||||||
selected = Map.get(selected_files, tab_id)
|
|
||||||
|
|
||||||
if selected in files do
|
|
||||||
selected
|
|
||||||
else
|
|
||||||
List.first(files)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp empty_git_diff(file_path) do
|
defp empty_git_diff(file_path) do
|
||||||
%{file_path: file_path, original: "", modified: "", error: nil}
|
%{file_path: file_path, original: "", modified: "", error: nil}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
<p><%= @misc_editor.subtitle %></p>
|
<p><%= @misc_editor.subtitle %></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="misc-editor-actions">
|
<div class="misc-editor-actions">
|
||||||
<button class="secondary" type="button" phx-click="rerun_misc_editor"><%= translated("Refresh") %></button>
|
<button class="secondary" type="button" phx-click="rerun_misc_editor" phx-target={@myself}><%= translated("Refresh") %></button>
|
||||||
<%= if @misc_editor.kind == :site_validation do %>
|
<%= if @misc_editor.kind == :site_validation do %>
|
||||||
<button class="primary" type="button" phx-click="apply_site_validation" disabled={Enum.empty?(@misc_editor.missing_url_paths) and Enum.empty?(@misc_editor.extra_url_paths) and Enum.empty?(@misc_editor.updated_post_url_paths)}><%= translated("Apply") %></button>
|
<button class="primary" type="button" phx-click="apply_site_validation" phx-target={@myself} disabled={Enum.empty?(@misc_editor.missing_url_paths) and Enum.empty?(@misc_editor.extra_url_paths) and Enum.empty?(@misc_editor.updated_post_url_paths)}><%= translated("Apply") %></button>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= if @misc_editor.kind == :find_duplicates do %>
|
<%= if @misc_editor.kind == :find_duplicates do %>
|
||||||
<button class="secondary" type="button" phx-click="dismiss_selected_duplicates" disabled={MapSet.size(@misc_editor.selected_pairs) == 0}><%= translated("Dismiss Checked") %></button>
|
<button class="secondary" type="button" phx-click="dismiss_selected_duplicates" phx-target={@myself} disabled={MapSet.size(@misc_editor.selected_pairs) == 0}><%= translated("Dismiss Checked") %></button>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
data-entity-tab={tab.id}
|
data-entity-tab={tab.id}
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="select_metadata_diff_tab"
|
phx-click="select_metadata_diff_tab"
|
||||||
|
phx-target={@myself}
|
||||||
phx-value-tab={tab.id}
|
phx-value-tab={tab.id}
|
||||||
>
|
>
|
||||||
<span><%= tab.label %></span>
|
<span><%= tab.label %></span>
|
||||||
@@ -60,6 +61,7 @@
|
|||||||
data-field={field.field_name}
|
data-field={field.field_name}
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="toggle_metadata_diff_field"
|
phx-click="toggle_metadata_diff_field"
|
||||||
|
phx-target={@myself}
|
||||||
phx-value-field={field.field_name}
|
phx-value-field={field.field_name}
|
||||||
>
|
>
|
||||||
<span class="field-pill-label"><%= field.field_name %></span>
|
<span class="field-pill-label"><%= field.field_name %></span>
|
||||||
@@ -75,6 +77,7 @@
|
|||||||
data-field={field.field_name}
|
data-field={field.field_name}
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="repair_metadata_diff"
|
phx-click="repair_metadata_diff"
|
||||||
|
phx-target={@myself}
|
||||||
phx-value-direction="db_to_file"
|
phx-value-direction="db_to_file"
|
||||||
phx-value-field={field.field_name}
|
phx-value-field={field.field_name}
|
||||||
>
|
>
|
||||||
@@ -88,6 +91,7 @@
|
|||||||
data-field={field.field_name}
|
data-field={field.field_name}
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="repair_metadata_diff"
|
phx-click="repair_metadata_diff"
|
||||||
|
phx-target={@myself}
|
||||||
phx-value-direction="file_to_db"
|
phx-value-direction="file_to_db"
|
||||||
phx-value-field={field.field_name}
|
phx-value-field={field.field_name}
|
||||||
>
|
>
|
||||||
@@ -149,6 +153,7 @@
|
|||||||
data-testid="metadata-diff-import-button"
|
data-testid="metadata-diff-import-button"
|
||||||
type="button"
|
type="button"
|
||||||
phx-click="import_metadata_diff_orphans"
|
phx-click="import_metadata_diff_orphans"
|
||||||
|
phx-target={@myself}
|
||||||
>
|
>
|
||||||
<%= translated("Import") %>
|
<%= translated("Import") %>
|
||||||
</button>
|
</button>
|
||||||
@@ -251,8 +256,8 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="translation-validation-actions">
|
<div class="translation-validation-actions">
|
||||||
<button class="secondary" type="button" phx-click="rerun_misc_editor" data-testid="translation-validation-revalidate"><%= translated("translationValidation.revalidate") %></button>
|
<button class="secondary" type="button" phx-click="rerun_misc_editor" phx-target={@myself} data-testid="translation-validation-revalidate"><%= translated("translationValidation.revalidate") %></button>
|
||||||
<button class="primary" type="button" phx-click="fix_translation_validation" data-testid="translation-validation-fix" disabled={not @misc_editor.can_fix?}><%= translated("translationValidation.fix") %></button>
|
<button class="primary" type="button" phx-click="fix_translation_validation" phx-target={@myself} data-testid="translation-validation-fix" disabled={not @misc_editor.can_fix?}><%= translated("translationValidation.fix") %></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -260,12 +265,12 @@
|
|||||||
<div class="misc-list">
|
<div class="misc-list">
|
||||||
<%= for pair <- @misc_editor.pairs do %>
|
<%= for pair <- @misc_editor.pairs do %>
|
||||||
<article class="misc-list-item duplicate-pair-row">
|
<article class="misc-list-item duplicate-pair-row">
|
||||||
<label><input type="checkbox" checked={duplicate_checked?(@misc_editor, pair_id_from_pair(pair))} phx-click="toggle_duplicate_pair" phx-value-pair-id={pair_id_from_pair(pair)} /> <span></span></label>
|
<label><input type="checkbox" checked={duplicate_checked?(@misc_editor, pair_id_from_pair(pair))} phx-click="toggle_duplicate_pair" phx-target={@myself} phx-value-pair-id={pair_id_from_pair(pair)} /> <span></span></label>
|
||||||
<button class="linkish" type="button" phx-click="open_duplicate_post" phx-value-id={BDS.MapUtils.attr(pair, :post_id_a)} phx-value-title={BDS.MapUtils.attr(pair, :title_a)}><%= BDS.MapUtils.attr(pair, :title_a) %></button>
|
<button class="linkish" type="button" phx-click="open_duplicate_post" phx-target={@myself} phx-value-id={BDS.MapUtils.attr(pair, :post_id_a)} phx-value-title={BDS.MapUtils.attr(pair, :title_a)}><%= BDS.MapUtils.attr(pair, :title_a) %></button>
|
||||||
<span>→</span>
|
<span>→</span>
|
||||||
<button class="linkish" type="button" phx-click="open_duplicate_post" phx-value-id={BDS.MapUtils.attr(pair, :post_id_b)} phx-value-title={BDS.MapUtils.attr(pair, :title_b)}><%= BDS.MapUtils.attr(pair, :title_b) %></button>
|
<button class="linkish" type="button" phx-click="open_duplicate_post" phx-target={@myself} phx-value-id={BDS.MapUtils.attr(pair, :post_id_b)} phx-value-title={BDS.MapUtils.attr(pair, :title_b)}><%= BDS.MapUtils.attr(pair, :title_b) %></button>
|
||||||
<span class="misc-summary-pill"><%= if(BDS.MapUtils.attr(pair, :exact_match), do: translated("Exact Match"), else: "#{Float.round((BDS.MapUtils.attr(pair, :similarity) || 0.0) * 100, 1)}%") %></span>
|
<span class="misc-summary-pill"><%= if(BDS.MapUtils.attr(pair, :exact_match), do: translated("Exact Match"), else: "#{Float.round((BDS.MapUtils.attr(pair, :similarity) || 0.0) * 100, 1)}%") %></span>
|
||||||
<button class="secondary" type="button" phx-click="dismiss_duplicate_pair" phx-value-post-id-a={BDS.MapUtils.attr(pair, :post_id_a)} phx-value-post-id-b={BDS.MapUtils.attr(pair, :post_id_b)}><%= translated("Dismiss") %></button>
|
<button class="secondary" type="button" phx-click="dismiss_duplicate_pair" phx-target={@myself} phx-value-post-id-a={BDS.MapUtils.attr(pair, :post_id_a)} phx-value-post-id-b={BDS.MapUtils.attr(pair, :post_id_b)}><%= translated("Dismiss") %></button>
|
||||||
</article>
|
</article>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
@@ -275,7 +280,7 @@
|
|||||||
<%= if @misc_editor.files == [] do %>
|
<%= if @misc_editor.files == [] do %>
|
||||||
<p class="git-diff-empty"><%= @misc_editor.empty_message %></p>
|
<p class="git-diff-empty"><%= @misc_editor.empty_message %></p>
|
||||||
<% else %>
|
<% else %>
|
||||||
<form class="git-diff-toolbar" phx-change="select_git_diff_file">
|
<form class="git-diff-toolbar" phx-change="select_git_diff_file" phx-target={@myself}>
|
||||||
<label for="git-diff-file-select"><%= translated("gitDiff.changedFiles") %></label>
|
<label for="git-diff-file-select"><%= translated("gitDiff.changedFiles") %></label>
|
||||||
<select id="git-diff-file-select" data-testid="git-diff-file-select" name="path">
|
<select id="git-diff-file-select" data-testid="git-diff-file-select" name="path">
|
||||||
<%= for file_path <- @misc_editor.files do %>
|
<%= for file_path <- @misc_editor.files do %>
|
||||||
|
|||||||
@@ -1872,13 +1872,13 @@ defmodule BDS.Desktop.ShellLiveTest do
|
|||||||
|
|
||||||
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
||||||
|
|
||||||
html =
|
|
||||||
view
|
view
|
||||||
|> element(
|
|> element(
|
||||||
"[data-testid='metadata-diff-repair-button'][data-direction='file_to_db'][data-field='title']"
|
"[data-testid='metadata-diff-repair-button'][data-direction='file_to_db'][data-field='title']"
|
||||||
)
|
)
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
|
html = render(view)
|
||||||
assert html =~ "Repair Metadata Diff"
|
assert html =~ "Repair Metadata Diff"
|
||||||
|
|
||||||
repair_task = new_task!(existing_ids, "Repair Metadata Diff")
|
repair_task = new_task!(existing_ids, "Repair Metadata Diff")
|
||||||
@@ -2000,11 +2000,11 @@ defmodule BDS.Desktop.ShellLiveTest do
|
|||||||
|
|
||||||
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
||||||
|
|
||||||
html =
|
|
||||||
view
|
view
|
||||||
|> element("[data-testid='metadata-diff-import-button']")
|
|> element("[data-testid='metadata-diff-import-button']")
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
|
html = render(view)
|
||||||
assert html =~ "Import Metadata Diff Orphans"
|
assert html =~ "Import Metadata Diff Orphans"
|
||||||
|
|
||||||
import_task = new_task!(existing_ids, "Import Metadata Diff Orphans")
|
import_task = new_task!(existing_ids, "Import Metadata Diff Orphans")
|
||||||
@@ -2055,13 +2055,13 @@ defmodule BDS.Desktop.ShellLiveTest do
|
|||||||
|
|
||||||
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
existing_ids = MapSet.new(Enum.map(BDS.Tasks.list_tasks(), & &1.id))
|
||||||
|
|
||||||
html =
|
|
||||||
view
|
view
|
||||||
|> element(
|
|> element(
|
||||||
"[data-testid='metadata-diff-repair-button'][data-direction='file_to_db'][data-field='content_hash']"
|
"[data-testid='metadata-diff-repair-button'][data-direction='file_to_db'][data-field='content_hash']"
|
||||||
)
|
)
|
||||||
|> render_click()
|
|> render_click()
|
||||||
|
|
||||||
|
html = render(view)
|
||||||
assert html =~ "Repair Metadata Diff"
|
assert html =~ "Repair Metadata Diff"
|
||||||
|
|
||||||
repair_task = new_task!(existing_ids, "Repair Metadata Diff")
|
repair_task = new_task!(existing_ids, "Repair Metadata Diff")
|
||||||
|
|||||||
Reference in New Issue
Block a user