chore: more god module work
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
290
lib/bds/desktop/shell_live/panel_renderer.ex
Normal file
290
lib/bds/desktop/shell_live/panel_renderer.ex
Normal file
@@ -0,0 +1,290 @@
|
||||
defmodule BDS.Desktop.ShellLive.PanelRenderer do
|
||||
@moduledoc false
|
||||
|
||||
use Phoenix.Component
|
||||
|
||||
alias BDS.Desktop.ShellData
|
||||
alias BDS.Git
|
||||
alias BDS.Media.Media
|
||||
alias BDS.PostLinks
|
||||
alias BDS.Posts.Post
|
||||
alias BDS.Repo
|
||||
|
||||
@doc "Render the active panel tab body."
|
||||
def render_panel_body(assigns) do
|
||||
case assigns.workbench.panel.active_tab do
|
||||
:tasks -> render_task_entries(assigns)
|
||||
:output -> render_output_entries(assigns)
|
||||
:post_links -> render_post_links(assigns)
|
||||
:git_log -> render_git_log(assigns)
|
||||
other -> render_generic_panel(assigns, other)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "Render the editor toolbar for the current tab."
|
||||
def render_editor_toolbar(assigns) do
|
||||
buttons = editor_toolbar_buttons(assigns.current_tab)
|
||||
assigns = assign(assigns, :editor_toolbar_buttons, buttons)
|
||||
|
||||
~H"""
|
||||
<%= if Enum.any?(@editor_toolbar_buttons) do %>
|
||||
<div class="editor-toolbar">
|
||||
<%= for button <- @editor_toolbar_buttons do %>
|
||||
<button
|
||||
class={["editor-toolbar-button", if(button.destructive, do: "is-destructive")]}
|
||||
data-testid="editor-toolbar-overlay-button"
|
||||
type="button"
|
||||
phx-click="open_overlay"
|
||||
phx-value-kind={button.kind}
|
||||
>
|
||||
<%= translated(button.label) %>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_task_entries(assigns) do
|
||||
~H"""
|
||||
<%= if Enum.empty?(Map.get(@task_status, :tasks, [])) do %>
|
||||
<div class="panel-entry panel-empty-state">
|
||||
<strong><%= translated("Tasks") %></strong>
|
||||
<span><%= translated("No background tasks running") %></span>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="task-list">
|
||||
<%= for task <- Map.get(@task_status, :tasks, []) do %>
|
||||
<div class="panel-entry task-entry">
|
||||
<div class="task-entry-header">
|
||||
<strong><%= task.name %></strong>
|
||||
<span class={"task-status task-status-#{task.status}"}><%= Map.get(task, :status_label, task.status |> to_string() |> String.capitalize()) %></span>
|
||||
</div>
|
||||
<span><%= task.message || task.group_name || "" %></span>
|
||||
<%= if is_number(task.progress) do %>
|
||||
<div class="task-progress-row">
|
||||
<progress max="1" value={task.progress}></progress>
|
||||
<span><%= Map.get(task, :progress_label, progress_percent(task.progress)) %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_output_entries(assigns) do
|
||||
~H"""
|
||||
<%= if Enum.empty?(@output_entries) do %>
|
||||
<div class="panel-entry panel-empty-state output-list">
|
||||
<strong><%= translated("Output") %></strong>
|
||||
<span><%= translated("No shell output yet") %></span>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="output-list">
|
||||
<%= for entry <- @output_entries do %>
|
||||
<div class={[
|
||||
"panel-entry",
|
||||
"output-entry",
|
||||
if(Map.get(entry, :level) == "error", do: "output-entry-error")
|
||||
]}>
|
||||
<strong><%= entry.title %></strong>
|
||||
<span><%= entry.message %></span>
|
||||
<%= if present?(entry.details) do %>
|
||||
<span><%= entry.details %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_post_links(assigns) do
|
||||
links = post_link_entries(assigns)
|
||||
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(:backlinks, Map.get(links, :backlinks, []))
|
||||
|> assign(:outlinks, Map.get(links, :outlinks, []))
|
||||
|
||||
~H"""
|
||||
<%= if Enum.empty?(@backlinks) and Enum.empty?(@outlinks) do %>
|
||||
<div class="panel-entry panel-empty-state">
|
||||
<strong><%= translated("Post Links") %></strong>
|
||||
<span><%= translated("No post links yet") %></span>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="git-log-list">
|
||||
<%= if Enum.any?(@backlinks) do %>
|
||||
<div class="panel-entry"><strong><%= translated("Backlinks") %></strong></div>
|
||||
<%= for entry <- @backlinks do %>
|
||||
<button
|
||||
class="panel-entry task-entry"
|
||||
type="button"
|
||||
phx-click="pin_sidebar_item"
|
||||
phx-value-route="post"
|
||||
phx-value-id={entry.id}
|
||||
phx-value-title={entry.title}
|
||||
phx-value-subtitle="linked post"
|
||||
>
|
||||
<strong><%= entry.title %></strong>
|
||||
<span><%= entry.text %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= if Enum.any?(@outlinks) do %>
|
||||
<div class="panel-entry"><strong><%= translated("Links To") %></strong></div>
|
||||
<%= for entry <- @outlinks do %>
|
||||
<button
|
||||
class="panel-entry task-entry"
|
||||
type="button"
|
||||
phx-click="pin_sidebar_item"
|
||||
phx-value-route="post"
|
||||
phx-value-id={entry.id}
|
||||
phx-value-title={entry.title}
|
||||
phx-value-subtitle="linked post"
|
||||
>
|
||||
<strong><%= entry.title %></strong>
|
||||
<span><%= entry.text %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_git_log(assigns) do
|
||||
entries = git_log_entries(assigns)
|
||||
assigns = assign(assigns, :git_entries, entries)
|
||||
|
||||
~H"""
|
||||
<%= if Enum.empty?(@git_entries) do %>
|
||||
<div class="git-log-list">
|
||||
<div class="panel-entry panel-empty-state">
|
||||
<strong><%= translated("Git Log") %></strong>
|
||||
<span><%= translated("No git history yet") %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="git-log-list">
|
||||
<%= for entry <- @git_entries do %>
|
||||
<div class="panel-entry task-entry">
|
||||
<strong><%= short_commit_hash(entry.hash) %> <%= entry.subject || translated("No commit subject") %></strong>
|
||||
<span><%= entry.hash %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_generic_panel(assigns, tab) do
|
||||
assigns = assign(assigns, :panel_label, ShellData.route_label(tab))
|
||||
|
||||
~H"""
|
||||
<div class="panel-entry">
|
||||
<strong><%= @panel_label %></strong>
|
||||
<span><%= translated("The shared lower panel is available for tasks, output, git details, and editor-specific diagnostics.") %></span>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp post_link_entries(assigns) do
|
||||
case assigns.current_tab do
|
||||
%{type: :post, id: post_id} ->
|
||||
%{
|
||||
backlinks: related_posts(PostLinks.list_incoming_links(post_id), :source_post_id),
|
||||
outlinks: related_posts(PostLinks.list_outgoing_links(post_id), :target_post_id)
|
||||
}
|
||||
|
||||
_other ->
|
||||
%{backlinks: [], outlinks: []}
|
||||
end
|
||||
end
|
||||
|
||||
defp related_posts(links, key) do
|
||||
Enum.map(links, fn link ->
|
||||
case Repo.get(Post, Map.fetch!(link, key)) do
|
||||
%Post{} = post -> %{id: post.id, title: post.title || post.slug || post.id, text: link.link_text || post.slug || post.id}
|
||||
_other -> nil
|
||||
end
|
||||
end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
end
|
||||
|
||||
defp git_log_entries(assigns) do
|
||||
case git_history_target(assigns.current_tab) do
|
||||
nil ->
|
||||
[]
|
||||
|
||||
{project_id, file_path} ->
|
||||
case Git.file_history(project_id, file_path) do
|
||||
{:ok, %{commits: commits}} -> commits
|
||||
_other -> []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp git_history_target(%{type: :post, id: post_id}) do
|
||||
case Repo.get(Post, post_id) do
|
||||
%Post{project_id: project_id, file_path: file_path} when file_path not in [nil, ""] -> {project_id, file_path}
|
||||
_other -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp git_history_target(%{type: :media, id: media_id}) do
|
||||
case Repo.get(Media, media_id) do
|
||||
%Media{project_id: project_id, file_path: file_path} when file_path not in [nil, ""] -> {project_id, file_path}
|
||||
_other -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp git_history_target(_tab), do: nil
|
||||
|
||||
def editor_toolbar_buttons(nil), do: []
|
||||
|
||||
def editor_toolbar_buttons(%{type: :post}) do
|
||||
[
|
||||
%{kind: "ai_suggestions", label: "AI Suggestions", destructive: false},
|
||||
%{kind: "insert_link", label: "Insert Link", destructive: false},
|
||||
%{kind: "insert_media", label: "Insert Media", destructive: false},
|
||||
%{kind: "language_picker", label: "Translate", destructive: false},
|
||||
%{kind: "gallery", label: "Gallery", destructive: false}
|
||||
]
|
||||
end
|
||||
|
||||
def editor_toolbar_buttons(%{type: :media}) do
|
||||
[
|
||||
%{kind: "ai_suggestions", label: "AI Suggestions", destructive: false},
|
||||
%{kind: "language_picker", label: "Translate", destructive: false},
|
||||
%{kind: "confirm_delete", label: "Delete Media", destructive: true}
|
||||
]
|
||||
end
|
||||
|
||||
def editor_toolbar_buttons(%{type: :tags}) do
|
||||
[
|
||||
%{kind: "confirm_merge", label: "Merge Tags", destructive: false},
|
||||
%{kind: "confirm_delete", label: "Delete Tag", destructive: true}
|
||||
]
|
||||
end
|
||||
|
||||
def editor_toolbar_buttons(_tab), do: []
|
||||
|
||||
defp short_commit_hash(hash) when is_binary(hash), do: String.slice(hash, 0, 7)
|
||||
defp short_commit_hash(_hash), do: "-------"
|
||||
|
||||
defp progress_percent(progress) when is_number(progress) do
|
||||
rounded = progress |> Kernel.*(100) |> Float.round(0) |> trunc()
|
||||
"#{rounded}%"
|
||||
end
|
||||
|
||||
defp progress_percent(_), do: ""
|
||||
|
||||
defp present?(value), do: value not in [nil, ""]
|
||||
|
||||
defp translated(text, bindings \\ %{}), do: ShellData.translate(text, bindings, Process.get(:bds_ui_locale))
|
||||
end
|
||||
Reference in New Issue
Block a user