fix: issue #20 cmd-J panel tab strip visibility and output panel parity
This commit is contained in:
91
lib/bds/ui/task_grouping.ex
Normal file
91
lib/bds/ui/task_grouping.ex
Normal file
@@ -0,0 +1,91 @@
|
||||
defmodule BDS.UI.TaskGrouping do
|
||||
@moduledoc """
|
||||
Groups task snapshot entries for the bottom panel's Tasks tab, mirroring the
|
||||
old app's `taskGrouping.ts`: tasks sharing a `group_id` collapse into one
|
||||
group entry (ordered by first appearance), everything else stays a single
|
||||
entry. Groups summarize to per-status counts plus an aggregate progress in
|
||||
the 0.0..1.0 range.
|
||||
"""
|
||||
|
||||
@type task :: map()
|
||||
@type entry :: {:single, task()} | {:group, String.t(), String.t(), [task()]}
|
||||
@type summary :: %{
|
||||
total: non_neg_integer(),
|
||||
running: non_neg_integer(),
|
||||
pending: non_neg_integer(),
|
||||
completed: non_neg_integer(),
|
||||
failed: non_neg_integer(),
|
||||
cancelled: non_neg_integer(),
|
||||
progress: float()
|
||||
}
|
||||
|
||||
@spec build_task_entries([task()]) :: [entry()]
|
||||
def build_task_entries(tasks) when is_list(tasks) do
|
||||
{singles, groups} =
|
||||
tasks
|
||||
|> Enum.with_index()
|
||||
|> Enum.reduce({[], %{}}, fn {task, index}, {singles, groups} ->
|
||||
case Map.get(task, :group_id) do
|
||||
nil ->
|
||||
{[{index, task} | singles], groups}
|
||||
|
||||
group_id ->
|
||||
groups =
|
||||
Map.update(groups, group_id, {index, Map.get(task, :group_name) || group_id, [task]}, fn {first_index, name, grouped} ->
|
||||
{first_index, name, [task | grouped]}
|
||||
end)
|
||||
|
||||
{singles, groups}
|
||||
end
|
||||
end)
|
||||
|
||||
single_entries = Enum.map(singles, fn {index, task} -> {index, {:single, task}} end)
|
||||
|
||||
group_entries =
|
||||
Enum.map(groups, fn {group_id, {index, name, grouped}} ->
|
||||
{index, {:group, group_id, name, Enum.reverse(grouped)}}
|
||||
end)
|
||||
|
||||
(single_entries ++ group_entries)
|
||||
|> Enum.sort_by(fn {index, _entry} -> index end)
|
||||
|> Enum.map(fn {_index, entry} -> entry end)
|
||||
end
|
||||
|
||||
@spec summarize_task_group([task()]) :: summary()
|
||||
def summarize_task_group(tasks) when is_list(tasks) do
|
||||
base = %{total: 0, running: 0, pending: 0, completed: 0, failed: 0, cancelled: 0, progress: 0.0}
|
||||
|
||||
summary =
|
||||
Enum.reduce(tasks, base, fn task, acc ->
|
||||
status = Map.get(task, :status)
|
||||
|
||||
acc
|
||||
|> Map.update!(:total, &(&1 + 1))
|
||||
|> count_status(status)
|
||||
|> Map.update!(:progress, &(&1 + progress_contribution(task)))
|
||||
end)
|
||||
|
||||
if summary.total > 0 do
|
||||
%{summary | progress: summary.progress / summary.total}
|
||||
else
|
||||
summary
|
||||
end
|
||||
end
|
||||
|
||||
defp count_status(acc, status) when status in [:running, :pending, :completed, :failed, :cancelled],
|
||||
do: Map.update!(acc, status, &(&1 + 1))
|
||||
|
||||
defp count_status(acc, _status), do: acc
|
||||
|
||||
# Finished tasks count as fully done no matter their outcome, pending tasks
|
||||
# contribute nothing yet (old-app getProgressContribution).
|
||||
defp progress_contribution(%{status: status}) when status in [:completed, :failed, :cancelled],
|
||||
do: 1.0
|
||||
|
||||
defp progress_contribution(%{status: :pending}), do: 0.0
|
||||
|
||||
defp progress_contribution(%{progress: progress}) when is_number(progress),
|
||||
do: progress |> max(0.0) |> min(1.0)
|
||||
|
||||
defp progress_contribution(_task), do: 0.0
|
||||
end
|
||||
Reference in New Issue
Block a user