refactor
This commit is contained in:
parent
e0f0ca369c
commit
d34ff57531
6 changed files with 127 additions and 391 deletions
|
|
@ -45,6 +45,9 @@ defmodule MvWeb.ImportExportLive do
|
|||
# after this limit is reached.
|
||||
@max_errors 50
|
||||
|
||||
# Maximum length for error messages before truncation
|
||||
@max_error_message_length 200
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
# Get locale from session for translations
|
||||
|
|
@ -95,11 +98,11 @@ defmodule MvWeb.ImportExportLive do
|
|||
<%= if Authorization.can?(@current_user, :create, Mv.Membership.Member) do %>
|
||||
<%!-- CSV Import Section --%>
|
||||
<.form_section title={gettext("Import Members (CSV)")}>
|
||||
<%= import_info_box(assigns) %>
|
||||
<%= template_links(assigns) %>
|
||||
<%= import_form(assigns) %>
|
||||
{import_info_box(assigns)}
|
||||
{template_links(assigns)}
|
||||
{import_form(assigns)}
|
||||
<%= if @import_status == :running or @import_status == :done do %>
|
||||
<%= import_progress(assigns) %>
|
||||
{import_progress(assigns)}
|
||||
<% end %>
|
||||
</.form_section>
|
||||
|
||||
|
|
@ -243,7 +246,7 @@ defmodule MvWeb.ImportExportLive do
|
|||
<% end %>
|
||||
|
||||
<%= if @import_progress.status == :done do %>
|
||||
<%= import_results(assigns) %>
|
||||
{import_results(assigns)}
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
@ -487,9 +490,7 @@ defmodule MvWeb.ImportExportLive do
|
|||
|
||||
# Formats Ash validation errors for display
|
||||
defp format_ash_error(%Ash.Error.Invalid{errors: errors}) when is_list(errors) do
|
||||
errors
|
||||
|> Enum.map(&format_single_error/1)
|
||||
|> Enum.join(", ")
|
||||
Enum.map_join(errors, ", ", &format_single_error/1)
|
||||
end
|
||||
|
||||
defp format_ash_error(error) do
|
||||
|
|
@ -498,9 +499,7 @@ defmodule MvWeb.ImportExportLive do
|
|||
|
||||
# Formats a list of errors into a readable string
|
||||
defp format_error_list(errors) do
|
||||
errors
|
||||
|> Enum.map(&format_single_error/1)
|
||||
|> Enum.join(", ")
|
||||
Enum.map_join(errors, ", ", &format_single_error/1)
|
||||
end
|
||||
|
||||
# Formats a single error item
|
||||
|
|
@ -516,8 +515,8 @@ defmodule MvWeb.ImportExportLive do
|
|||
defp format_unknown_error(other) do
|
||||
error_str = inspect(other, limit: :infinity, pretty: true)
|
||||
|
||||
if String.length(error_str) > 200 do
|
||||
String.slice(error_str, 0, 197) <> "..."
|
||||
if String.length(error_str) > @max_error_message_length do
|
||||
String.slice(error_str, 0, @max_error_message_length - 3) <> "..."
|
||||
else
|
||||
error_str
|
||||
end
|
||||
|
|
@ -558,6 +557,49 @@ defmodule MvWeb.ImportExportLive do
|
|||
handle_chunk_error(socket, :processing_failed, idx, reason)
|
||||
end
|
||||
|
||||
# Processes a chunk with error handling and sends result message to LiveView.
|
||||
#
|
||||
# Handles errors from MemberCSV.process_chunk and sends appropriate messages
|
||||
# to the LiveView process for progress tracking.
|
||||
@spec process_chunk_with_error_handling(
|
||||
list(),
|
||||
map(),
|
||||
map(),
|
||||
keyword(),
|
||||
pid(),
|
||||
non_neg_integer()
|
||||
) :: :ok
|
||||
defp process_chunk_with_error_handling(
|
||||
chunk,
|
||||
column_map,
|
||||
custom_field_map,
|
||||
opts,
|
||||
live_view_pid,
|
||||
idx
|
||||
) do
|
||||
result =
|
||||
try do
|
||||
MemberCSV.process_chunk(chunk, column_map, custom_field_map, opts)
|
||||
rescue
|
||||
e ->
|
||||
{:error, Exception.message(e)}
|
||||
catch
|
||||
:exit, reason ->
|
||||
{:error, inspect(reason)}
|
||||
|
||||
:throw, reason ->
|
||||
{:error, inspect(reason)}
|
||||
end
|
||||
|
||||
case result do
|
||||
{:ok, chunk_result} ->
|
||||
send(live_view_pid, {:chunk_done, idx, chunk_result})
|
||||
|
||||
{:error, reason} ->
|
||||
send(live_view_pid, {:chunk_error, idx, reason})
|
||||
end
|
||||
end
|
||||
|
||||
# Starts async task to process a chunk of CSV rows.
|
||||
#
|
||||
# In tests (SQL sandbox mode), runs synchronously to avoid Ecto Sandbox issues.
|
||||
|
|
@ -586,33 +628,16 @@ defmodule MvWeb.ImportExportLive do
|
|||
|
||||
if Config.sql_sandbox?() do
|
||||
# Run synchronously in tests to avoid Ecto Sandbox issues with async tasks
|
||||
result =
|
||||
try do
|
||||
MemberCSV.process_chunk(
|
||||
chunk,
|
||||
import_state.column_map,
|
||||
import_state.custom_field_map,
|
||||
opts
|
||||
)
|
||||
rescue
|
||||
e ->
|
||||
{:error, Exception.message(e)}
|
||||
catch
|
||||
:exit, reason ->
|
||||
{:error, inspect(reason)}
|
||||
:throw, reason ->
|
||||
{:error, inspect(reason)}
|
||||
end
|
||||
|
||||
case result do
|
||||
{:ok, chunk_result} ->
|
||||
# In test mode, send the message - it will be processed when render() is called
|
||||
# in the test. The test helper wait_for_import_completion() handles message processing
|
||||
send(live_view_pid, {:chunk_done, idx, chunk_result})
|
||||
|
||||
{:error, reason} ->
|
||||
send(live_view_pid, {:chunk_error, idx, reason})
|
||||
end
|
||||
# In test mode, send the message - it will be processed when render() is called
|
||||
# in the test. The test helper wait_for_import_completion() handles message processing
|
||||
process_chunk_with_error_handling(
|
||||
chunk,
|
||||
import_state.column_map,
|
||||
import_state.custom_field_map,
|
||||
opts,
|
||||
live_view_pid,
|
||||
idx
|
||||
)
|
||||
else
|
||||
# Start async task to process chunk in production
|
||||
# Use start_child for fire-and-forget: no monitor, no Task messages
|
||||
|
|
@ -621,31 +646,14 @@ defmodule MvWeb.ImportExportLive do
|
|||
# Set locale in task process for translations
|
||||
Gettext.put_locale(MvWeb.Gettext, locale)
|
||||
|
||||
result =
|
||||
try do
|
||||
MemberCSV.process_chunk(
|
||||
chunk,
|
||||
import_state.column_map,
|
||||
import_state.custom_field_map,
|
||||
opts
|
||||
)
|
||||
rescue
|
||||
e ->
|
||||
{:error, Exception.message(e)}
|
||||
catch
|
||||
:exit, reason ->
|
||||
{:error, inspect(reason)}
|
||||
:throw, reason ->
|
||||
{:error, inspect(reason)}
|
||||
end
|
||||
|
||||
case result do
|
||||
{:ok, chunk_result} ->
|
||||
send(live_view_pid, {:chunk_done, idx, chunk_result})
|
||||
|
||||
{:error, reason} ->
|
||||
send(live_view_pid, {:chunk_error, idx, reason})
|
||||
end
|
||||
process_chunk_with_error_handling(
|
||||
chunk,
|
||||
import_state.column_map,
|
||||
import_state.custom_field_map,
|
||||
opts,
|
||||
live_view_pid,
|
||||
idx
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
@ -712,8 +720,14 @@ defmodule MvWeb.ImportExportLive do
|
|||
@spec consume_and_read_csv(Phoenix.LiveView.Socket.t()) ::
|
||||
{:ok, String.t()} | {:error, String.t()}
|
||||
defp consume_and_read_csv(socket) do
|
||||
case consume_uploaded_entries(socket, :csv_file, &read_file_entry/2) do
|
||||
[{:ok, content}] ->
|
||||
raw = consume_uploaded_entries(socket, :csv_file, &read_file_entry/2)
|
||||
|
||||
case raw do
|
||||
[{:ok, content}] when is_binary(content) ->
|
||||
{:ok, content}
|
||||
|
||||
# Phoenix LiveView test (render_upload) can return raw content list when callback return is treated as value
|
||||
[content] when is_binary(content) ->
|
||||
{:ok, content}
|
||||
|
||||
[{:error, reason}] ->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue