fix: add @spec to all public functions across 24 modules (CSM-019)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 11:40:42 +02:00
parent 3f77488e33
commit b6f9cf58e1
24 changed files with 150 additions and 3 deletions

View File

@@ -31,6 +31,7 @@ defmodule BDS.UI.Commands do
%{id: :upload_site, accelerator: "CTRL+SHIFT+U"}
]
@spec handle_shortcut(BDS.UI.Workbench.t(), map()) :: BDS.UI.Workbench.t()
def handle_shortcut(state, shortcut) when is_map(shortcut) do
case command_for_shortcut(shortcut) do
nil -> state
@@ -38,6 +39,7 @@ defmodule BDS.UI.Commands do
end
end
@spec command_for_shortcut(map()) :: atom() | nil
def command_for_shortcut(shortcut) when is_map(shortcut) do
key = shortcut |> BDS.MapUtils.attr(:key, "") |> String.downcase()
@@ -54,6 +56,7 @@ defmodule BDS.UI.Commands do
end
end
@spec client_shortcuts() :: [map()]
def client_shortcuts do
@menu_shortcuts
|> Enum.filter(&Map.has_key?(&1, :key))
@@ -67,6 +70,7 @@ defmodule BDS.UI.Commands do
end)
end
@spec accelerator_label(atom()) :: String.t() | nil
def accelerator_label(command_id) when is_atom(command_id) do
case Enum.find(@menu_shortcuts, &(&1.id == command_id)) do
%{accelerator: accelerator} -> accelerator

View File

@@ -8,6 +8,7 @@ defmodule BDS.UI.Dashboard do
alias BDS.Repo
alias BDS.Tags.Tag
@spec snapshot(String.t() | nil) :: map()
def snapshot(nil), do: empty_snapshot()
def snapshot(project_id) when is_binary(project_id) do
@@ -23,6 +24,7 @@ defmodule BDS.UI.Dashboard do
}
end
@spec empty_snapshot() :: map()
def empty_snapshot do
%{
title: "dashboard.title",

View File

@@ -4,6 +4,7 @@ defmodule BDS.UI.MenuBar do
alias BDS.UI.Registry
alias BDS.UI.Workbench
@spec default_groups(keyword()) :: [map()]
def default_groups(opts \\ []) do
dev_mode? = Keyword.get(opts, :dev_mode?, false)
@@ -80,6 +81,7 @@ defmodule BDS.UI.MenuBar do
]
end
@spec execute(Workbench.t(), atom()) :: Workbench.t()
def execute(state, :toggle_sidebar), do: Workbench.toggle_sidebar(state)
def execute(state, :toggle_panel), do: Workbench.toggle_panel(state)
def execute(state, :toggle_assistant_sidebar), do: Workbench.toggle_assistant_sidebar(state)

View File

@@ -3,8 +3,10 @@ defmodule BDS.UI.Registry do
use Gettext, backend: BDS.Gettext
@spec default_sidebar_view() :: atom()
def default_sidebar_view, do: :posts
@spec sidebar_views() :: [map()]
def sidebar_views do
[
%{
@@ -90,6 +92,7 @@ defmodule BDS.UI.Registry do
]
end
@spec editor_routes() :: [map()]
def editor_routes do
[
%{id: :dashboard, singleton: true, entity_tab: false, title: dgettext("ui", "Dashboard")},
@@ -138,6 +141,8 @@ defmodule BDS.UI.Registry do
]
end
@spec sidebar_view(atom()) :: map() | nil
def sidebar_view(id) when is_atom(id), do: Enum.find(sidebar_views(), &(&1.id == id))
@spec editor_route(atom()) :: map() | nil
def editor_route(id) when is_atom(id), do: Enum.find(editor_routes(), &(&1.id == id))
end

View File

@@ -4,6 +4,7 @@ defmodule BDS.UI.Session do
alias BDS.BoundedAtoms
alias BDS.UI.Workbench
@spec serialize(Workbench.t()) :: map()
def serialize(state) do
%{
"sidebar_visible" => state.sidebar_visible,
@@ -28,6 +29,7 @@ defmodule BDS.UI.Session do
}
end
@spec restore(map()) :: Workbench.t()
def restore(payload) when is_map(payload) do
state =
Workbench.new(

View File

@@ -16,6 +16,7 @@ defmodule BDS.UI.Sidebar do
@default_page_size 500
@spec snapshot(String.t() | nil) :: map()
def snapshot(nil), do: empty_snapshot()
def snapshot(project_id) when is_binary(project_id) do
@@ -39,6 +40,7 @@ defmodule BDS.UI.Sidebar do
}
end
@spec view(String.t() | nil, String.t() | atom(), map()) :: map()
def view(project_id, view_id, params \\ %{})
def view(nil, view_id, _params), do: empty_view(view_id)
@@ -102,6 +104,7 @@ defmodule BDS.UI.Sidebar do
end
end
@spec empty_snapshot() :: map()
def empty_snapshot do
%{
"posts" => empty_view("posts"),

View File

@@ -19,6 +19,8 @@ defmodule BDS.UI.Workbench do
:find_duplicates
])
@type t :: %__MODULE__{}
defstruct sidebar_visible: true,
sidebar_width: 280,
active_view: :posts,
@@ -30,6 +32,7 @@ defmodule BDS.UI.Workbench do
editor_route: :dashboard,
dirty_tabs: MapSet.new()
@spec new(keyword()) :: t()
def new(opts \\ []) do
%__MODULE__{
sidebar_visible: Keyword.get(opts, :sidebar_visible, true),
@@ -48,14 +51,17 @@ defmodule BDS.UI.Workbench do
|> normalize_panel()
end
@spec set_sidebar_width(t(), integer()) :: t()
def set_sidebar_width(state, width) when is_integer(width) do
%{state | sidebar_width: clamp_sidebar_width(width)}
end
@spec set_assistant_sidebar_width(t(), integer()) :: t()
def set_assistant_sidebar_width(state, width) when is_integer(width) do
%{state | assistant_sidebar_width: clamp_assistant_sidebar_width(width)}
end
@spec open_tab(t(), atom() | String.t(), String.t(), atom()) :: t()
def open_tab(state, type, id, intent) do
{tabs, opened_tab} = upsert_tab(state.tabs, normalize_type(type), id, intent)
@@ -66,6 +72,7 @@ defmodule BDS.UI.Workbench do
|> normalize_panel()
end
@spec open_tab_in_background(t(), atom() | String.t(), String.t(), atom()) :: t()
def open_tab_in_background(state, type, id, intent) do
current_active = state.active_tab
{tabs, _opened_tab} = upsert_tab(state.tabs, normalize_type(type), id, intent)
@@ -77,6 +84,7 @@ defmodule BDS.UI.Workbench do
|> normalize_panel()
end
@spec close_tab(t(), atom() | String.t(), String.t()) :: t()
def close_tab(state, type, id) do
type = normalize_type(type)
target = {type, id}
@@ -103,6 +111,7 @@ defmodule BDS.UI.Workbench do
end
end
@spec pin_tab(t(), atom() | String.t(), String.t()) :: t()
def pin_tab(state, type, id) do
type = normalize_type(type)
@@ -114,11 +123,13 @@ defmodule BDS.UI.Workbench do
%{state | tabs: tabs}
end
@spec clear_tabs(t()) :: t()
def clear_tabs(state) do
%{state | tabs: [], active_tab: nil, editor_route: :dashboard, dirty_tabs: MapSet.new()}
|> normalize_panel()
end
@spec mark_dirty(t(), atom() | String.t(), String.t()) :: t()
def mark_dirty(state, type, id) do
if normalize_type(type) == :post do
%{state | dirty_tabs: MapSet.put(state.dirty_tabs, {normalize_type(type), id})}
@@ -127,32 +138,40 @@ defmodule BDS.UI.Workbench do
end
end
@spec clear_dirty(t(), atom() | String.t(), String.t()) :: t()
def clear_dirty(state, type, id) do
%{state | dirty_tabs: MapSet.delete(state.dirty_tabs, {normalize_type(type), id})}
end
@spec dirty?(t(), atom() | String.t(), String.t()) :: boolean()
def dirty?(state, type, id) do
MapSet.member?(state.dirty_tabs, {normalize_type(type), id})
end
@spec toggle_sidebar(t()) :: t()
def toggle_sidebar(state), do: %{state | sidebar_visible: not state.sidebar_visible}
@spec set_panel_visible(t(), boolean()) :: t()
def set_panel_visible(state, visible) when is_boolean(visible) do
%{state | panel: %{state.panel | visible: visible}}
end
@spec toggle_panel(t()) :: t()
def toggle_panel(state) do
set_panel_visible(state, not state.panel.visible)
end
@spec toggle_assistant_sidebar(t()) :: t()
def toggle_assistant_sidebar(state) do
%{state | assistant_sidebar_visible: not state.assistant_sidebar_visible}
end
@spec set_panel_tab(t(), atom()) :: t()
def set_panel_tab(state, tab) when tab in [:tasks, :output, :post_links, :git_log] do
%{state | panel: %{state.panel | active_tab: tab}}
end
@spec click_activity(t(), atom() | String.t()) :: t()
def click_activity(state, activity_id) do
activity_id = normalize_type(activity_id)
@@ -163,6 +182,7 @@ defmodule BDS.UI.Workbench do
end
end
@spec activity_buttons(t(), integer()) :: [map()]
def activity_buttons(state, git_badge_count \\ 0) do
Registry.sidebar_views()
|> Enum.map(fn view ->
@@ -176,6 +196,7 @@ defmodule BDS.UI.Workbench do
end)
end
@spec status_bar(t(), keyword()) :: map()
def status_bar(state, opts) do
post_count = Keyword.get(opts, :post_count, 0)
media_count = Keyword.get(opts, :media_count, 0)