style: fix pre-existing formatting drift across codebase

This commit is contained in:
2026-05-30 09:00:29 +02:00
parent 7045b10738
commit 2bed225133
44 changed files with 452 additions and 194 deletions

View File

@@ -10,7 +10,8 @@ if config_env() == :prod do
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "1")
# Persist downloaded embedding model files alongside the database data dir.
config :bumblebee, :cache_dir,
System.get_env("BDS_MODEL_CACHE_DIR") ||
Path.join(Path.dirname(Path.expand(database_path)), "models")
config :bumblebee,
:cache_dir,
System.get_env("BDS_MODEL_CACHE_DIR") ||
Path.join(Path.dirname(Path.expand(database_path)), "models")
end

View File

@@ -27,7 +27,9 @@ defmodule BDS.AI.ChatConversation do
def changeset(conversation, attrs) do
conversation
|> cast(attrs, [:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at],
|> cast(
attrs,
[:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at],
empty_values: [nil]
)
|> validate_required([:id, :title, :created_at, :updated_at])

View File

@@ -263,8 +263,13 @@ defmodule BDS.Desktop.Overlay do
def set_ai_suggestions_error(overlay, _error_message), do: overlay
defp normalize_ai_fields(fields) do
Enum.map(fields, fn %{key: key, label: label, current_value: current,
suggested_value: suggested, locked: locked} = field ->
Enum.map(fields, fn %{
key: key,
label: label,
current_value: current,
suggested_value: suggested,
locked: locked
} = field ->
%{
key: to_string(key),
label: label,

View File

@@ -103,7 +103,9 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
socket
) do
next_data = Map.put(socket.assigns.surface_data, surface_id, fields)
{:noreply, assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()}
{:noreply,
assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()}
end
def handle_event(
@@ -227,8 +229,11 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
build_data(socket)
socket.assigns.offline_mode ->
Notify.output(dgettext("ui", "Chat"),
dgettext("ui", "Automatic AI actions stay gated by airplane mode."), "info")
Notify.output(
dgettext("ui", "Chat"),
dgettext("ui", "Automatic AI actions stay gated by airplane mode."),
"info"
)
build_data(socket)

View File

@@ -35,14 +35,28 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
known_refs = MapSet.new(tasks, & &1.ref)
drain_tasks(
remaining, tasks, known_refs, project_id, post_id, language, translate_targets, parent
remaining,
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
send(parent, {:add_images_complete, length(paths)})
end
defp drain_tasks(
[], tasks, _known_refs, _project_id, _post_id, _language, _translate_targets, _parent
[],
tasks,
_known_refs,
_project_id,
_post_id,
_language,
_translate_targets,
_parent
) do
Enum.each(tasks, fn task -> Task.await(task, :infinity) end)
end
@@ -65,7 +79,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
new_task =
Task.async(fn ->
process_single_image(
next_path, project_id, post_id, language, translate_targets, parent
next_path,
project_id,
post_id,
language,
translate_targets,
parent
)
end)
@@ -81,8 +100,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
)
else
drain_tasks(
[next_path | rest], tasks, known_refs,
project_id, post_id, language, translate_targets, parent
[next_path | rest],
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
end
@@ -93,7 +118,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
new_task =
Task.async(fn ->
process_single_image(
next_path, project_id, post_id, language, translate_targets, parent
next_path,
project_id,
post_id,
language,
translate_targets,
parent
)
end)
@@ -109,8 +139,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
)
else
drain_tasks(
[next_path | rest], tasks, known_refs,
project_id, post_id, language, translate_targets, parent
[next_path | rest],
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
end
end
@@ -124,16 +160,22 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
end
defp process_single_image(
path, project_id, post_id, language, translate_targets, parent
path,
project_id,
post_id,
language,
translate_targets,
parent
) do
with {:ok, media} <- Media.import_media(%{project_id: project_id, source_path: path}),
true <- String.starts_with?(media.mime_type || "", "image/"),
{:ok, result} <- AI.analyze_image(media.id, language: language),
{:ok, _updated} <- Media.update_media(media.id, %{
title: result.title,
alt: result.alt,
caption: result.caption
}),
{:ok, _updated} <-
Media.update_media(media.id, %{
title: result.title,
alt: result.alt,
caption: result.caption
}),
{:ok, _link} <- Media.link_media_to_post(media.id, post_id) do
translate_media_translations(media.id, translate_targets)
title = result.title || media.original_name

View File

@@ -642,7 +642,10 @@ defmodule BDS.Desktop.ShellLive.ImportEditor do
defp maybe_update_tab_meta(socket, name) do
title = name || dgettext("ui", "Untitled Import")
Notify.tab_meta(:import, socket.assigns.definition_id, title,
Notify.tab_meta(
:import,
socket.assigns.definition_id,
title,
dgettext(
"ui",
"Select a WordPress export file (WXR) and an uploads folder to analyze what would be imported."

View File

@@ -126,8 +126,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
Notify.dirty(:media, media.id, false)
Notify.tab_meta(:media, media.id, display_title(updated_media),
updated_media.original_name || updated_media.mime_type || "")
Notify.tab_meta(
:media,
media.id,
display_title(updated_media),
updated_media.original_name || updated_media.mime_type || ""
)
{:noreply, socket}
@@ -484,8 +488,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
Notify.dirty(:media, media.id, false)
Notify.tab_meta(:media, media.id, display_title(updated_media),
updated_media.original_name || updated_media.mime_type || "")
Notify.tab_meta(
:media,
media.id,
display_title(updated_media),
updated_media.original_name || updated_media.mime_type || ""
)
notify_output(socket, dgettext("ui", "Media"), dgettext("ui", "Media saved"))
socket

View File

@@ -471,8 +471,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id, record_title(record, refreshed_post),
Atom.to_string(record_status(record)))
Notify.tab_meta(
:post,
post.id,
record_title(record, refreshed_post),
Atom.to_string(record_status(record))
)
Notify.dirty(:post, post.id, false)
Notify.cancel_auto_save(:post, post.id)
@@ -511,8 +515,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id, record_title(record, refreshed_post),
Atom.to_string(record_status(record)))
Notify.tab_meta(
:post,
post.id,
record_title(record, refreshed_post),
Atom.to_string(record_status(record))
)
Notify.dirty(:post, post.id, false)
notify_output(socket, dgettext("ui", "Post"), dgettext("ui", "Post published"))
@@ -546,9 +554,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id,
Notify.tab_meta(
:post,
post.id,
restored_post.title || restored_post.slug || restored_post.id,
Atom.to_string(restored_post.status || :draft))
Atom.to_string(restored_post.status || :draft)
)
Notify.dirty(:post, post.id, false)
socket

View File

@@ -271,10 +271,10 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
end
end
attr :color, :string, default: nil
attr :presets, :list, required: true
attr :pick_event, :string, required: true
attr :target, :any, required: true
attr(:color, :string, default: nil)
attr(:presets, :list, required: true)
attr(:pick_event, :string, required: true)
attr(:target, :any, required: true)
defp colour_picker(assigns) do
~H"""

View File

@@ -584,7 +584,9 @@ defmodule BDS.Embeddings do
end
defp duplicate_pairs_with_rebuild(project_id, entries, on_progress) do
case Index.duplicate_pairs(project_id, entries, @duplicate_threshold, on_progress: on_progress) do
case Index.duplicate_pairs(project_id, entries, @duplicate_threshold,
on_progress: on_progress
) do
{:ok, pairs} ->
{:ok, pairs}

View File

@@ -155,7 +155,9 @@ defmodule BDS.Embeddings.Backends.Neural do
# Place model params/tensors on the Apple GPU (Metal) when accelerating with
# EMLX so the compiled inference pass actually runs on-device. EXLA manages
# its own device placement, so nothing to do there.
defp maybe_set_default_backend(:emlx), do: Nx.global_default_backend({EMLX.Backend, device: :gpu})
defp maybe_set_default_backend(:emlx),
do: Nx.global_default_backend({EMLX.Backend, device: :gpu})
defp maybe_set_default_backend(:exla), do: :ok
@doc false

View File

@@ -58,7 +58,11 @@ defmodule BDS.Embeddings.Index do
"""
def neighbors(project_id, query_label, query_vector, limit)
when is_binary(project_id) and is_integer(query_label) and is_binary(query_vector) do
GenServer.call(__MODULE__, {:neighbors, project_id, query_label, query_vector, limit}, :infinity)
GenServer.call(
__MODULE__,
{:neighbors, project_id, query_label, query_vector, limit},
:infinity
)
end
@doc """
@@ -167,7 +171,10 @@ defmodule BDS.Embeddings.Index do
defp build_entry(dimensions, entries) do
count = length(entries)
{:ok, index} = HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction)
{:ok, index} =
HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction)
:ok = HNSWLib.Index.set_ef(index, @ef_search)
tensor =

View File

@@ -82,9 +82,7 @@ defmodule BDS.Generation.Pagefind do
# Returns nil when the page is not marked, so unmarked pages are excluded
# from the index entirely (matching Pagefind semantics).
defp body_text(content) do
case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content,
return: :index
) do
case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content, return: :index) do
[{open_start, open_len}, {tag_start, tag_len}] ->
tag = binary_part(content, tag_start, tag_len)
region = scoped_region(content, tag, open_start + open_len)
@@ -117,7 +115,10 @@ defmodule BDS.Generation.Pagefind do
end
defp event_kind(rest, pos, tag) do
if String.starts_with?(binary_part(rest, pos, min(2 + byte_size(tag), byte_size(rest) - pos)), "</") do
if String.starts_with?(
binary_part(rest, pos, min(2 + byte_size(tag), byte_size(rest) - pos)),
"</"
) do
:close
else
:open

View File

@@ -240,7 +240,11 @@ defmodule BDS.Media do
|> Repo.insert_or_update!()
end) do
{:ok, updated_translation} ->
log_sidecar_error(write_translation_sidecar(project, media, updated_translation), media.id)
log_sidecar_error(
write_translation_sidecar(project, media, updated_translation),
media.id
)
:ok = Search.sync_media(media.id)
{:ok, updated_translation}

View File

@@ -178,7 +178,9 @@ defmodule BDS.Preview do
case kind do
:media ->
serve_file(safe_join(server.data_dir, Path.join(["media", relative_path])),
server: server, query_params: query_params)
server: server,
query_params: query_params
)
:generated ->
case BDS.Preview.Router.render_route(server.project_id, request_path) do
@@ -187,7 +189,9 @@ defmodule BDS.Preview do
:not_matched ->
serve_file(safe_join(Path.join(server.data_dir, "html"), relative_path),
server: server, query_params: query_params)
server: server,
query_params: query_params
)
end
end
end
@@ -240,7 +244,10 @@ defmodule BDS.Preview do
defp draft_preview_payload(post, query_params) do
requested_language = query_params |> Map.get("lang") |> normalize_requested_language()
effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories)
effective_slug =
post.template_slug ||
TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories)
case draft_preview_translation(post.id, requested_language, post.language) do
%Translation{} = translation ->

View File

@@ -132,6 +132,7 @@ defmodule BDS.Preview.Router do
defp render(project_id, {:home, page_number}, language, main_language, metadata) do
posts = load_published_list_posts(project_id, metadata)
posts = maybe_resolve_language(posts, language, main_language, project_id)
render_list(project_id, posts, page_number, metadata, language, main_language, %{kind: "core"})
end
@@ -193,7 +194,13 @@ defmodule BDS.Preview.Router do
})
end
defp render(project_id, {:day, year, month, day, page_number}, language, main_language, metadata) do
defp render(
project_id,
{:day, year, month, day, page_number},
language,
main_language,
metadata
) do
posts = load_published_posts_by_day(project_id, year, month, day)
posts = maybe_resolve_language(posts, language, main_language, project_id)
@@ -208,7 +215,8 @@ defmodule BDS.Preview.Router do
## Post rendering
defp render_post(project_id, post, language, main_language) do
{effective_record, body} = resolve_post_for_language(project_id, post, language, main_language)
{effective_record, body} =
resolve_post_for_language(project_id, post, language, main_language)
assigns = %{
id: effective_record.id,
@@ -220,7 +228,9 @@ defmodule BDS.Preview.Router do
_post_record: effective_record
}
effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories)
effective_slug =
post.template_slug ||
TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories)
case Rendering.render_post_page(project_id, effective_slug, assigns) do
{:ok, rendered} -> {:ok, rendered}
@@ -370,7 +380,8 @@ defmodule BDS.Preview.Router do
defp archive_page_title(%{kind: "date", year: y, month: m, day: d})
when is_integer(y) and is_integer(m) and is_integer(d),
do: "#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}"
do:
"#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}"
defp archive_page_title(%{kind: "date", year: y, month: m})
when is_integer(y) and is_integer(m),
@@ -504,7 +515,8 @@ defmodule BDS.Preview.Router do
if String.downcase(to_string(language)) == String.downcase(to_string(main_language)) do
posts
else
translations = load_translations_for_language(project_id, Enum.map(posts, & &1.id), language)
translations =
load_translations_for_language(project_id, Enum.map(posts, & &1.id), language)
Enum.map(posts, fn post ->
case Map.get(translations, post.id) do

View File

@@ -104,8 +104,9 @@ defmodule BDS.Projects do
end
@spec project_data_dir(Project.t()) :: String.t()
def project_data_dir(%Project{data_path: data_path}) when is_binary(data_path) and data_path != "",
do: data_path
def project_data_dir(%Project{data_path: data_path})
when is_binary(data_path) and data_path != "",
do: data_path
# A project without an explicit data_path resolves to its folder under the
# per-user default content location — never priv/data inside the repo

View File

@@ -43,12 +43,26 @@ defmodule BDS.Rendering.Filters do
_language_prefix,
context
) do
render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id)
render_markdown(
value,
canonical_post_paths,
canonical_media_paths,
language,
context,
post_id
)
end
@spec render_markdown(term(), map() | nil, map() | nil, String.t(), Liquex.Context.t(), term()) ::
String.t()
def render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id \\ nil) do
def render_markdown(
value,
canonical_post_paths,
canonical_media_paths,
language,
context,
post_id \\ nil
) do
value
|> to_string()
|> replace_built_in_macros(language, context, post_id)
@@ -161,7 +175,11 @@ defmodule BDS.Rendering.Filters do
else
{:error, reason, line} ->
require Logger
Logger.warning("Macro template parse failed (#{template_path}): #{reason} at line #{line}")
Logger.warning(
"Macro template parse failed (#{template_path}): #{reason} at line #{line}"
)
""
{:error, message} ->
@@ -365,8 +383,7 @@ defmodule BDS.Rendering.Filters do
"root_classes" => "macro-photo-archive",
"data_attrs" => [],
"months" => months,
"empty_label" =>
BDS.Gettext.lgettext(language, "render", "No photos found")
"empty_label" => BDS.Gettext.lgettext(language, "render", "No photos found")
},
context
)
@@ -391,8 +408,7 @@ defmodule BDS.Rendering.Filters do
"width" => Map.get(params, "width", width),
"height" => Map.get(params, "height", height),
"aria_label" => "Tag cloud",
"empty_label" =>
BDS.Gettext.lgettext(language, "render", "No tags")
"empty_label" => BDS.Gettext.lgettext(language, "render", "No tags")
},
context
)
@@ -456,9 +472,18 @@ defmodule BDS.Rendering.Filters do
defp group_by_media_month(media_records) do
month_names = %{
1 => "January", 2 => "February", 3 => "March", 4 => "April",
5 => "May", 6 => "June", 7 => "July", 8 => "August",
9 => "September", 10 => "October", 11 => "November", 12 => "December"
1 => "January",
2 => "February",
3 => "March",
4 => "April",
5 => "May",
6 => "June",
7 => "July",
8 => "August",
9 => "September",
10 => "October",
11 => "November",
12 => "December"
}
media_records
@@ -555,8 +580,10 @@ defmodule BDS.Rendering.Filters do
_ -> default
end
end
defp normalize_columns(value, _default, min, max) when is_integer(value),
do: value |> max(min) |> min(max)
defp normalize_columns(_value, default, _min, _max), do: default
defp parse_integer(value) when is_binary(value) do
@@ -565,6 +592,7 @@ defmodule BDS.Rendering.Filters do
_ -> nil
end
end
defp parse_integer(value) when is_integer(value), do: value
defp parse_integer(_value), do: nil
@@ -583,6 +611,7 @@ defmodule BDS.Rendering.Filters do
case DateTime.from_iso8601("#{year}-#{pad(month + 1)}-01T00:00:00Z") do
{:ok, dt, _} ->
dt |> DateTime.add(-1, :second) |> DateTime.to_date() |> Map.get(:day)
_ ->
31
end

View File

@@ -349,5 +349,4 @@ defmodule BDS.Rendering.ListArchive do
do: RenderMetadata.calendar_initial_month(post)
defp calendar_initial_month_from_posts([]), do: nil
end

View File

@@ -63,8 +63,12 @@ defmodule BDS.Scripting do
args,
Keyword.put(opts, :timeout, timeout)
) do
{:ok, nil} -> {:ok, ""}
{:ok, value} -> {:ok, to_string(value)}
{:ok, nil} ->
{:ok, ""}
{:ok, value} ->
{:ok, to_string(value)}
{:error, reason} ->
Logger.warning("execute_macro failed for project #{project_id}: #{inspect(reason)}")
{:error, reason}

View File

@@ -111,8 +111,7 @@ defmodule BDS.Scripting.Capabilities do
get_by_status: one_arg(fn status -> posts_by_status(project_id, status) end),
get_by_year_month: zero_or_one_arg(fn _args -> post_counts_by_year_month(project_id) end),
get_dashboard_stats: zero_or_one_arg(fn _args -> post_dashboard_stats(project_id) end),
get_linked_by:
one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end),
get_linked_by: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end),
get_links_to: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :outgoing) end),
get_preview_url:
two_arg(fn post_id, options -> preview_url(project_id, post_id, options) end),
@@ -157,8 +156,7 @@ defmodule BDS.Scripting.Capabilities do
end),
filter: one_arg(fn filters -> filter_media(project_id, filters) end),
import: one_arg(fn attrs -> import_media(project_id, attrs) end),
get_by_year_month:
zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end),
get_by_year_month: zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end),
get_file_path: one_arg(fn media_id -> media_file_path(project_id, media_id) end),
update: two_arg(fn media_id, attrs -> update_media(project_id, media_id, attrs) end),
delete: one_arg(fn media_id -> delete_media(project_id, media_id) end),
@@ -172,8 +170,7 @@ defmodule BDS.Scripting.Capabilities do
two_arg(fn media_id, language ->
load_media_translation(project_id, media_id, language)
end),
get_translations:
one_arg(fn media_id -> list_media_translations(project_id, media_id) end),
get_translations: one_arg(fn media_id -> list_media_translations(project_id, media_id) end),
get_url: one_arg(fn media_id -> media_url(project_id, media_id) end),
rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_media_from_files(project_id) end),
regenerate_missing_thumbnails:
@@ -201,8 +198,7 @@ defmodule BDS.Scripting.Capabilities do
get: one_arg(fn script_id -> load_script(project_id, script_id) end),
get_all: zero_or_one_arg(fn _args -> list_scripts(project_id) end),
publish: one_arg(fn script_id -> publish_script(project_id, script_id) end),
rebuild_from_files:
zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end)
rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end)
}
end
@@ -295,8 +291,7 @@ defmodule BDS.Scripting.Capabilities do
find_similar: two_arg(fn post_id, limit -> find_similar(post_id, limit) end),
compute_similarities:
two_arg(fn post_id, target_ids -> compute_similarities(post_id, target_ids) end),
suggest_tags:
two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end),
suggest_tags: two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end),
find_duplicates: zero_or_one_arg(fn _args -> find_duplicates(project_id) end),
dismiss_pair: two_arg(fn post_id_a, post_id_b -> dismiss_pair(post_id_a, post_id_b) end),
index_unindexed_posts: zero_or_one_arg(fn _args -> index_unindexed_posts(project_id) end)

View File

@@ -284,14 +284,24 @@ defmodule BDS.Search do
defp maybe_where_year(query, year) do
year_str = to_string(year)
where(query, [p], fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str))
where(
query,
[p],
fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str)
)
end
defp maybe_where_month(query, nil), do: query
defp maybe_where_month(query, month) do
month_str = String.pad_leading(to_string(month), 2, "0")
where(query, [p], fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str))
where(
query,
[p],
fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str)
)
end
defp maybe_where_from(query, nil), do: query
@@ -305,7 +315,10 @@ defmodule BDS.Search do
defp maybe_where_tags(query, tags) do
tags_clause =
Enum.reduce(tags, false, fn tag, acc ->
dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag))
dynamic(
[p],
^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag)
)
end)
where(query, [p], ^tags_clause)
@@ -316,7 +329,10 @@ defmodule BDS.Search do
defp maybe_where_tags_media(query, tags) do
tags_clause =
Enum.reduce(tags, false, fn tag, acc ->
dynamic([m], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag))
dynamic(
[m],
^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag)
)
end)
where(query, [m], ^tags_clause)
@@ -327,7 +343,15 @@ defmodule BDS.Search do
defp maybe_where_categories(query, categories) do
categories_clause =
Enum.reduce(categories, false, fn category, acc ->
dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.categories, ^category))
dynamic(
[p],
^acc or
fragment(
"EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)",
p.categories,
^category
)
)
end)
where(query, [p], ^categories_clause)
@@ -548,8 +572,6 @@ defmodule BDS.Search do
)
end
defp post_index_fields(post, translations) do
post_language = normalize_language(post.language)
@@ -656,8 +678,8 @@ defmodule BDS.Search do
else
Repo.all(
from translation in MediaTranslation,
where: translation.translation_for in ^media_ids,
select: {translation.translation_for, translation}
where: translation.translation_for in ^media_ids,
select: {translation.translation_for, translation}
)
|> Enum.group_by(fn {media_id, _} -> media_id end, fn {_, translation} -> translation end)
end

View File

@@ -239,6 +239,7 @@ defmodule BDS.Tags do
{:error, changeset} -> Repo.rollback(changeset)
end
end)
Enum.map(affected_posts, & &1.id)
end)
|> case do

View File

@@ -79,8 +79,14 @@ defmodule BDS.UI.Dashboard do
from post in Post,
where: post.project_id == ^project_id,
group_by: [
fragment("CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at),
fragment("CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at)
fragment(
"CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)",
post.created_at
),
fragment(
"CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)",
post.created_at
)
],
select: %{
year:

View File

@@ -51,7 +51,10 @@ defmodule BDS.CSM006NPlusOneTest do
end
# Clear FTS and reindex
Repo.query!("DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", [project.id])
Repo.query!(
"DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)",
[project.id]
)
# Reindex should succeed and produce correct FTS entries
assert :ok = BDS.Search.reindex_posts(project.id)
@@ -82,7 +85,11 @@ defmodule BDS.CSM006NPlusOneTest do
language: "en"
})
Repo.query!("DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)", [project.id])
Repo.query!(
"DELETE FROM posts_fts WHERE post_id IN (SELECT id FROM posts WHERE project_id = ?)",
[project.id]
)
assert :ok = BDS.Search.reindex_posts(project.id)
{:ok, results} = BDS.Search.search_posts(project.id, "unique-keyword-xyz")

View File

@@ -24,12 +24,13 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers no dashboard or git queries", %{project: _project} do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
query_count = count_queries(fn ->
render_click(view, "toggle_sidebar", %{})
end)
query_count =
count_queries(fn ->
render_click(view, "toggle_sidebar", %{})
end)
assert query_count == 0,
"Expected 0 DB queries for sidebar toggle, got #{query_count}"
"Expected 0 DB queries for sidebar toggle, got #{query_count}"
end
end
@@ -37,12 +38,13 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers no DB queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
query_count = count_queries(fn ->
render_click(view, "toggle_panel", %{})
end)
query_count =
count_queries(fn ->
render_click(view, "toggle_panel", %{})
end)
assert query_count == 0,
"Expected 0 DB queries for panel toggle, got #{query_count}"
"Expected 0 DB queries for panel toggle, got #{query_count}"
end
end
@@ -50,16 +52,17 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers no DB queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
query_count = count_queries(fn ->
render_click(view, "sync_layout", %{
"sidebar_width" => "300",
"sidebar_visible" => "true",
"panel_visible" => "false"
})
end)
query_count =
count_queries(fn ->
render_click(view, "sync_layout", %{
"sidebar_width" => "300",
"sidebar_visible" => "true",
"panel_visible" => "false"
})
end)
assert query_count == 0,
"Expected 0 DB queries for sync_layout, got #{query_count}"
"Expected 0 DB queries for sync_layout, got #{query_count}"
end
end
@@ -67,12 +70,13 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers no DB queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
query_count = count_queries(fn ->
render_click(view, "select_panel_tab", %{"tab" => "output"})
end)
query_count =
count_queries(fn ->
render_click(view, "select_panel_tab", %{"tab" => "output"})
end)
assert query_count == 0,
"Expected 0 DB queries for select_panel_tab, got #{query_count}"
"Expected 0 DB queries for select_panel_tab, got #{query_count}"
end
end
@@ -80,14 +84,15 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers sidebar query but not dashboard or git queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
{query_count, query_sources} = count_queries_with_sources(fn ->
render_click(view, "select_view", %{"view" => "media"})
end)
{query_count, query_sources} =
count_queries_with_sources(fn ->
render_click(view, "select_view", %{"view" => "media"})
end)
assert query_count > 0, "Expected at least 1 query for view change"
refute "dashboard" in query_sources or "projects" in query_sources,
"View change should not query dashboard or projects, got: #{inspect(query_sources)}"
"View change should not query dashboard or projects, got: #{inspect(query_sources)}"
end
end
@@ -95,14 +100,15 @@ defmodule BDS.CSM007ReloadShellTest do
test "do not trigger dashboard or git queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
{_count, query_sources} = count_queries_with_sources(fn ->
render_click(view, "update_sidebar_search", %{
"sidebar_filters" => %{"search" => "test"}
})
end)
{_count, query_sources} =
count_queries_with_sources(fn ->
render_click(view, "update_sidebar_search", %{
"sidebar_filters" => %{"search" => "test"}
})
end)
refute "dashboard" in query_sources,
"Sidebar search should not query dashboard, got: #{inspect(query_sources)}"
"Sidebar search should not query dashboard, got: #{inspect(query_sources)}"
end
end
@@ -110,12 +116,13 @@ defmodule BDS.CSM007ReloadShellTest do
test "triggers only the settings write, no refresh queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
query_count = count_queries(fn ->
render_click(view, "toggle_offline_mode", %{})
end)
query_count =
count_queries(fn ->
render_click(view, "toggle_offline_mode", %{})
end)
assert query_count == 1,
"Expected exactly 1 DB query (settings write) for offline mode toggle, got #{query_count}"
"Expected exactly 1 DB query (settings write) for offline mode toggle, got #{query_count}"
end
end

View File

@@ -37,12 +37,13 @@ defmodule BDS.CSM008RenderPathTest do
render_click(view, "select_tab", %{"type" => "post", "id" => post.id})
render_click(view, "select_panel_tab", %{"tab" => "post_links"})
query_count = count_queries(fn ->
1..10 |> Enum.each(fn _ -> render(view) end)
end)
query_count =
count_queries(fn ->
1..10 |> Enum.each(fn _ -> render(view) end)
end)
assert query_count == 0,
"Expected 0 DB queries on panel re-renders, got #{query_count}"
"Expected 0 DB queries on panel re-renders, got #{query_count}"
end
test "git_log panel re-render uses cached assigns", %{post: post} do
@@ -51,12 +52,13 @@ defmodule BDS.CSM008RenderPathTest do
render_click(view, "select_tab", %{"type" => "post", "id" => post.id})
render_click(view, "select_panel_tab", %{"tab" => "git_log"})
query_count = count_queries(fn ->
1..10 |> Enum.each(fn _ -> render(view) end)
end)
query_count =
count_queries(fn ->
1..10 |> Enum.each(fn _ -> render(view) end)
end)
assert query_count == 0,
"Expected 0 DB queries on git_log re-renders, got #{query_count}"
"Expected 0 DB queries on git_log re-renders, got #{query_count}"
end
end
@@ -64,26 +66,28 @@ defmodule BDS.CSM008RenderPathTest do
test "switching to output panel triggers no post/media queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
{query_count, query_sources} = count_queries_with_sources(fn ->
render_click(view, "select_panel_tab", %{"tab" => "output"})
end)
{query_count, query_sources} =
count_queries_with_sources(fn ->
render_click(view, "select_panel_tab", %{"tab" => "output"})
end)
refute "post_links" in query_sources,
"Switching to output should not query post_links, got: #{inspect(query_sources)}"
"Switching to output should not query post_links, got: #{inspect(query_sources)}"
assert query_count == 0,
"Expected 0 queries for output panel tab, got #{query_count}"
"Expected 0 queries for output panel tab, got #{query_count}"
end
test "switching to tasks panel triggers no post/media queries" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
{query_count, _query_sources} = count_queries_with_sources(fn ->
render_click(view, "select_panel_tab", %{"tab" => "tasks"})
end)
{query_count, _query_sources} =
count_queries_with_sources(fn ->
render_click(view, "select_panel_tab", %{"tab" => "tasks"})
end)
assert query_count == 0,
"Expected 0 queries for tasks panel tab, got #{query_count}"
"Expected 0 queries for tasks panel tab, got #{query_count}"
end
end
@@ -98,12 +102,13 @@ defmodule BDS.CSM008RenderPathTest do
"subtitle" => "preset subtitle"
})
query_count = count_queries(fn ->
render_click(view, "select_tab", %{"type" => "post", "id" => post.id})
end)
query_count =
count_queries(fn ->
render_click(view, "select_tab", %{"type" => "post", "id" => post.id})
end)
assert query_count == 0,
"Expected 0 DB queries when tab meta is already complete, got #{query_count}"
"Expected 0 DB queries when tab meta is already complete, got #{query_count}"
end
end

View File

@@ -34,7 +34,10 @@ defmodule BDS.CSM009ThumbnailErrorHandlingTest do
assert {:error, _reason} = result
end
test "ensure_thumbnails returns :ok for non-image media", %{project: project, temp_dir: temp_dir} do
test "ensure_thumbnails returns :ok for non-image media", %{
project: project,
temp_dir: temp_dir
} do
source_path = Path.join(temp_dir, "readme.txt")
File.write!(source_path, "just text")
@@ -86,11 +89,15 @@ defmodule BDS.CSM009ThumbnailErrorHandlingTest do
} do
source_path = Path.join(temp_dir, "good.jpg")
File.write!(source_path, tiny_jpeg_binary())
{:ok, good_media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path})
{:ok, good_media} =
BDS.Media.import_media(%{project_id: project.id, source_path: source_path})
corrupt_path = Path.join(temp_dir, "bad.jpg")
File.write!(corrupt_path, "corrupt data")
{:ok, bad_media} = BDS.Media.import_media(%{project_id: project.id, source_path: corrupt_path})
{:ok, bad_media} =
BDS.Media.import_media(%{project_id: project.id, source_path: corrupt_path})
Enum.each(Map.values(Thumbnails.thumbnail_paths(good_media)), fn path ->
File.rm(Path.join(temp_dir, path))

View File

@@ -79,7 +79,9 @@ defmodule BDS.CSM020NestedCaseTest do
describe "Publishing.handle_call :update_job uses with" do
test "source code uses with instead of case" do
source = File.read!("lib/bds/publishing.ex")
[func_source] = Regex.scan(~r/def handle_call\(\{:update_job.*?(?=\n def |\n @impl)/s, source)
[func_source] =
Regex.scan(~r/def handle_call\(\{:update_job.*?(?=\n def |\n @impl)/s, source)
assert func_source |> List.first() |> String.contains?("with"),
"update_job handler should use with"

View File

@@ -4,6 +4,7 @@ defmodule BDS.CSM031TryRescueTest do
describe "source-level: no inline try/rescue around Liquex.render!" do
test "filters.ex has no try/rescue block in render_macro_source" do
source = File.read!("lib/bds/rendering/filters.ex")
refute source =~ ~r/try do\s+.*Liquex\.render!/s,
"render_macro_source should use safe_liquex_render helper, not inline try/rescue"
end
@@ -51,6 +52,7 @@ defmodule BDS.CSM031TryRescueTest do
test "template_selection.ex uses FileSystem.try_read instead of read_template_file" do
source = File.read!("lib/bds/rendering/template_selection.ex")
refute source =~ "read_template_file",
"should use FileSystem.try_read, not the raising read_template_file"

View File

@@ -35,12 +35,14 @@ defmodule BDS.CSM032MapGetPatternMatchTest do
describe "source-level: overlay.ex uses pattern matching for known structures" do
test "delete_details uses pattern matching instead of Map.get" do
source = File.read!("lib/bds/desktop/overlay.ex")
refute source =~ "Map.get(delete_details,",
"overlay.ex should pattern match delete_details instead of using Map.get"
end
test "merge_details uses pattern matching instead of Map.get" do
source = File.read!("lib/bds/desktop/overlay.ex")
refute source =~ "Map.get(merge,",
"overlay.ex should pattern match merge_details instead of using Map.get"
end
@@ -65,32 +67,40 @@ defmodule BDS.CSM032MapGetPatternMatchTest do
describe "source-level: generation pipeline uses dot access for Post struct fields" do
test "outputs.ex uses post.language instead of Map.get(post, :language)" do
source = File.read!("lib/bds/generation/outputs.ex")
refute source =~ "Map.get(post, :language)",
"outputs.ex should use post.language"
end
test "data.ex uses dot access for Post struct fields in build_published_translation_variant" do
source = File.read!("lib/bds/generation/data.ex")
refute source =~ "Map.get(post, :author)",
"data.ex should use post.author"
refute source =~ "Map.get(post, :tags",
"data.ex should use post.tags"
refute source =~ "Map.get(post, :categories",
"data.ex should use post.categories"
refute source =~ "Map.get(post, :template_slug)",
"data.ex should use post.template_slug"
refute source =~ "Map.get(post, :do_not_translate",
"data.ex should use post.do_not_translate"
end
test "validation.ex uses post.file_path instead of Map.get(post, :file_path)" do
source = File.read!("lib/bds/generation/validation.ex")
refute source =~ "Map.get(post, :file_path)",
"validation.ex should use post.file_path"
end
test "sitemap.ex uses post.do_not_translate instead of Map.get" do
source = File.read!("lib/bds/generation/sitemap.ex")
refute source =~ "Map.get(post, :do_not_translate)",
"sitemap.ex should use post.do_not_translate"
end

View File

@@ -118,9 +118,7 @@ defmodule BDS.CSM033BatchInsertsTest do
assert Enum.all?(posts, fn post -> post.id in indexed end)
keys =
BDS.Repo.all(
from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id)
)
BDS.Repo.all(from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id))
assert length(keys) == 5
labels = Enum.map(keys, & &1.label) |> Enum.sort()
@@ -141,7 +139,8 @@ defmodule BDS.CSM033BatchInsertsTest do
original_key =
BDS.Repo.get_by!(BDS.Embeddings.Key, project_id: project.id, post_id: post.id)
{:ok, _post} = BDS.Posts.update_post(post.id, %{content: "completely different content now"})
{:ok, _post} =
BDS.Posts.update_post(post.id, %{content: "completely different content now"})
{:ok, rebuilt_ids} = BDS.Embeddings.rebuild_project(project.id)
assert post.id in rebuilt_ids
@@ -175,9 +174,7 @@ defmodule BDS.CSM033BatchInsertsTest do
assert repaired == [post_a.id]
keys =
BDS.Repo.all(
from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id)
)
BDS.Repo.all(from(k in BDS.Embeddings.Key, where: k.project_id == ^project.id))
assert length(keys) == 2
end
@@ -206,5 +203,4 @@ defmodule BDS.CSM033BatchInsertsTest do
assert key_before.vector == key_after.vector
end
end
end

View File

@@ -21,7 +21,9 @@ defmodule BDS.CSM034FileReadBangTest do
test "release_packaging.ex has no File.read! or File.write!" do
source = File.read!("lib/bds/release_packaging.ex")
refute source =~ "File.read!", "release_packaging.ex should use File.read, not File.read!"
refute source =~ "File.write!", "release_packaging.ex should use File.write, not File.write!"
refute source =~ "File.write!",
"release_packaging.ex should use File.write, not File.write!"
end
end

View File

@@ -49,7 +49,9 @@ defmodule BDS.CSM035ProcessDictTest do
match = Regex.run(~r/def sidebar_content\(assigns\).*?\n(.*?)\n/s, source)
assert match, "could not find sidebar_content/1"
[_, first_line | _] = match
assert first_line =~ "UILocale.put", "sidebar_content/1 must call UILocale.put on its first line"
assert first_line =~ "UILocale.put",
"sidebar_content/1 must call UILocale.put on its first line"
end
test "MenuBar.mount/1 calls UILocale.put" do
@@ -57,7 +59,9 @@ defmodule BDS.CSM035ProcessDictTest do
match = Regex.run(~r/def mount\(menu\).*?\n(.*?)\n/s, source)
assert match, "could not find mount/1 in menu_bar.ex"
[_, first_line | _] = match
assert first_line =~ "UILocale.put", "MenuBar.mount/1 must call UILocale.put on its first line"
assert first_line =~ "UILocale.put",
"MenuBar.mount/1 must call UILocale.put on its first line"
end
end

View File

@@ -100,7 +100,9 @@ defmodule BDS.Desktop.AutomationTest do
assert :ok = Automation.reload(session)
snapshot = await(session, &(&1.sidebar_visible == true and &1.sidebar_width >= resized_width - 2))
snapshot =
await(session, &(&1.sidebar_visible == true and &1.sidebar_width >= resized_width - 2))
assert snapshot.sidebar_visible == true
assert snapshot.sidebar_width >= resized_width - 2
assert snapshot.sidebar_width <= resized_width + 2

View File

@@ -315,9 +315,15 @@ defmodule BDS.DesktopTest do
assert conn.resp_body =~ ~s(data-testid="toggle-sidebar")
assert conn.resp_body =~ ~s(data-testid="toggle-panel")
assert conn.resp_body =~ ~s(data-testid="toggle-assistant")
assert conn.resp_body =~ ~s(class="activity-bar flex h-full shrink-0 flex-col items-center justify-between")
assert conn.resp_body =~
~s(class="activity-bar flex h-full shrink-0 flex-col items-center justify-between")
assert conn.resp_body =~ ~s(class="sidebar flex min-w-0 flex-1 overflow-hidden")
assert conn.resp_body =~ ~s(class="status-bar flex h-[22px] shrink-0 items-center justify-between gap-2")
assert conn.resp_body =~
~s(class="status-bar flex h-[22px] shrink-0 items-center justify-between gap-2")
assert conn.resp_body =~ ~s(data-phx-main)
assert conn.resp_body =~ ~s(href="/assets/app.css")
assert conn.resp_body =~ ~s(src="/assets/app.js")

View File

@@ -19,7 +19,9 @@ defmodule BDS.ImageImportPipelineTest do
File.mkdir_p!(temp_dir)
on_exit(fn -> File.rm_rf(temp_dir) end)
{:ok, project} = BDS.Projects.create_project(%{name: "Image Import Test", data_path: temp_dir})
{:ok, project} =
BDS.Projects.create_project(%{name: "Image Import Test", data_path: temp_dir})
%{project: project, temp_dir: temp_dir}
end
@@ -40,7 +42,8 @@ defmodule BDS.ImageImportPipelineTest do
)
assert result ==
{:ok, ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]}
{:ok,
["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]}
end
test "multi selection filters out empty lines" do
@@ -51,7 +54,8 @@ defmodule BDS.ImageImportPipelineTest do
)
assert result ==
{:ok, ["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]}
{:ok,
["/Users/test/photo1.jpg", "/Users/test/photo2.png", "/Users/test/photo3.heic"]}
end
test "multi selection with single file returns list with one element" do

View File

@@ -32,7 +32,10 @@ defmodule BDS.ImportDefinitionsTest do
result = ImportDefinitions.decode_analysis_result(malicious_json)
assert is_map(result)
assert Map.get(result, unknown_key_1) == "val" or Map.get(result, "csm001_fictive_#{unique_suffix}") == "val"
assert Map.get(result, unknown_key_1) == "val" or
Map.get(result, "csm001_fictive_#{unique_suffix}") == "val"
assert_raise ArgumentError, fn -> String.to_existing_atom(unknown_key_1) end
assert_raise ArgumentError, fn -> String.to_existing_atom(unknown_key_2) end
end

View File

@@ -83,9 +83,10 @@ defmodule BDS.MapUtilsTest do
test "safe_atomize_keys does not create atoms for malicious payloads" do
unique_suffix = :erlang.unique_integer()
malicious = for i <- 1..500, into: %{} do
{"csm001_malicious_#{i}_#{unique_suffix}", "val"}
end
malicious =
for i <- 1..500, into: %{} do
{"csm001_malicious_#{i}_#{unique_suffix}", "val"}
end
result = MapUtils.safe_atomize_keys(malicious)

View File

@@ -229,6 +229,7 @@ defmodule BDS.PostsTest do
File.write!(old_full, "stale content")
import Ecto.Query
BDS.Repo.update_all(
from(p in BDS.Posts.Post, where: p.id == ^published.id),
set: [file_path: old_relative, content: "edited body"]

View File

@@ -424,9 +424,10 @@ defmodule BDS.PreviewTest do
assert :ok = BDS.Preview.stop_preview(project.id)
end
test "on-demand rendering: published post route renders via template without generated files", %{
project: project
} do
test "on-demand rendering: published post route renders via template without generated files",
%{
project: project
} do
assert {:ok, _metadata} =
Metadata.update_project_metadata(project.id, %{
main_language: "en",
@@ -458,9 +459,10 @@ defmodule BDS.PreviewTest do
assert :ok = BDS.Preview.stop_preview(project.id)
end
test "on-demand rendering: home page renders published posts as list without generated files", %{
project: project
} do
test "on-demand rendering: home page renders published posts as list without generated files",
%{
project: project
} do
assert {:ok, _metadata} =
Metadata.update_project_metadata(project.id, %{
main_language: "en",

View File

@@ -96,7 +96,9 @@ defmodule BDS.Scripts.TransformsTest do
data.content = data.content .. "D"
return data
end
""", enabled: false)
""",
enabled: false
)
transform(other.id, "Foreign", """
function main(data, _ctx)

View File

@@ -142,7 +142,8 @@ defmodule BDS.TemplateLookupPriorityTest do
describe "BundledDefaultTemplatesExistOutsideProjectData" do
test "single-post bundled template resolves with no Template rows", %{project: project} do
assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
assert [] =
BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
{:ok, source} = TemplateSelection.load_template_source(project.id, :post, nil)
@@ -150,7 +151,8 @@ defmodule BDS.TemplateLookupPriorityTest do
end
test "post-list bundled template resolves with no Template rows", %{project: project} do
assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
assert [] =
BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
{:ok, source} = TemplateSelection.load_template_source(project.id, :list, nil)
@@ -158,7 +160,8 @@ defmodule BDS.TemplateLookupPriorityTest do
end
test "not-found bundled template resolves with no Template rows", %{project: project} do
assert [] = BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
assert [] =
BDS.Repo.all(from t in BDS.Templates.Template, where: t.project_id == ^project.id)
{:ok, source} = TemplateSelection.load_template_source(project.id, :not_found, nil)

View File

@@ -175,25 +175,39 @@ defmodule BDS.UI.ShellTest do
test "phase 3 templates use shared shell and form primitives for common layout" do
post_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/post_editor_html/post_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/post_editor_html/post_editor.html.heex"
)
media_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/media_editor_html/media_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/media_editor_html/media_editor.html.heex"
)
script_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/script_editor_html/script_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/script_editor_html/script_editor.html.heex"
)
template_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/template_editor_html/template_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/template_editor_html/template_editor.html.heex"
)
chat_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/chat_editor_html/chat_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/chat_editor_html/chat_editor.html.heex"
)
menu_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/menu_editor_html/menu_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/menu_editor_html/menu_editor.html.heex"
)
settings_template =
File.read!("/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/settings_editor_html/settings_editor.html.heex")
File.read!(
"/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live/settings_editor_html/settings_editor.html.heex"
)
assert post_template =~ "ui-editor-shell"
assert post_template =~ "ui-editor-header"
@@ -248,8 +262,12 @@ defmodule BDS.UI.ShellTest do
assistant_css = File.read!("/Users/gb/Projects/bDS2/assets/css/assistant.css")
menu_css = File.read!("/Users/gb/Projects/bDS2/assets/css/menu_editor.css")
refute editor_css =~ ".post-editor .editor-header,\n.scripts-view-shell.editor .editor-header,\n.templates-view-shell.editor .editor-header {\n display: flex;"
refute editor_css =~ ".post-editor .editor-actions,\n.scripts-view-shell.editor .editor-actions,\n.templates-view-shell.editor .editor-actions {\n display: flex;"
refute editor_css =~
".post-editor .editor-header,\n.scripts-view-shell.editor .editor-header,\n.templates-view-shell.editor .editor-header {\n display: flex;"
refute editor_css =~
".post-editor .editor-actions,\n.scripts-view-shell.editor .editor-actions,\n.templates-view-shell.editor .editor-actions {\n display: flex;"
refute editor_css =~ ".post-editor .quick-actions-menu {"
refute media_css =~ "[data-testid=\"media-editor\"] .editor-header {"
refute media_css =~ "[data-testid=\"media-editor\"] .editor-actions {"
@@ -287,9 +305,14 @@ defmodule BDS.UI.ShellTest do
assert css =~ ".chat-panel .chat-input-container"
assert css =~ ".chat-model-selector-menu"
assert css =~ "@media (max-width: 720px) {\n .chat-panel-header {\n align-items: stretch;\n flex-direction: column;"
assert css =~
"@media (max-width: 720px) {\n .chat-panel-header {\n align-items: stretch;\n flex-direction: column;"
assert css =~ ".chat-model-selector-wrap {\n width: 100%;"
assert css =~ ".chat-panel .chat-model-selector-button.chat-model-selector-inline {\n justify-content: space-between;\n width: 100%;"
assert css =~
".chat-panel .chat-model-selector-button.chat-model-selector-inline {\n justify-content: space-between;\n width: 100%;"
assert css =~ ".chat-panel .chat-input-container {\n padding: 8px 12px;"
end