feat: more UI cleanup

This commit is contained in:
2026-04-24 18:22:25 +02:00
parent e51566d707
commit 6824b89691
11 changed files with 696 additions and 3 deletions

View File

@@ -114,6 +114,64 @@ defmodule BDS.DesktopTest do
end)
end
test "desktop router exposes projects for shell project selection and creation" do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
BDS.Repo.delete_all(BDS.Projects.Project)
internal_projects_root = "/Users/gb/Projects/bDS2/priv/data/projects"
before_internal_dirs =
case File.ls(internal_projects_root) do
{:ok, entries} -> MapSet.new(entries)
{:error, :enoent} -> MapSet.new()
end
temp_dir = Path.join(System.tmp_dir!(), "bds-desktop-projects-#{System.unique_integer([:positive])}")
File.mkdir_p!(temp_dir)
on_exit(fn ->
File.rm_rf(temp_dir)
end)
{:ok, project} = BDS.Projects.create_project(%{name: "Desktop Projects", data_path: temp_dir})
{:ok, _active} = BDS.Projects.set_active_project(project.id)
conn = conn(:get, "/api/projects?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
payload = Jason.decode!(conn.resp_body)
assert payload["active_project_id"] == project.id
assert Enum.any?(payload["projects"], &(&1["id"] == project.id and &1["name"] == "Desktop Projects"))
assert Enum.any?(payload["projects"], &(&1["id"] == "default" and &1["name"] == "My Blog"))
created_data_dir = Path.join(temp_dir, "created-from-shell")
create_conn =
conn(
:post,
"/api/projects?k=#{Desktop.Auth.login_key()}",
Jason.encode!(%{"name" => "Created From Shell", "data_path" => created_data_dir})
)
|> Plug.Conn.put_req_header("content-type", "application/json")
create_conn = BDS.Desktop.Router.call(create_conn, BDS.Desktop.Router.init([]))
assert create_conn.status == 200
created_payload = Jason.decode!(create_conn.resp_body)
assert created_payload["project"]["name"] == "Created From Shell"
assert created_payload["active_project_id"] == created_payload["project"]["id"]
assert created_payload["project"]["data_path"] == created_data_dir
after_internal_dirs =
case File.ls(internal_projects_root) do
{:ok, entries} -> MapSet.new(entries)
{:error, :enoent} -> MapSet.new()
end
assert after_internal_dirs == before_internal_dirs
end
test "desktop router executes shell commands through the JSON api" do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
:ok = Ecto.Adapters.SQL.Sandbox.allow(BDS.Repo, self(), Process.whereis(BDS.Preview))

View File

@@ -0,0 +1,70 @@
defmodule BDS.Repo.BootstrapTest do
use ExUnit.Case, async: false
alias BDS.Projects.Project
defmodule TempRepo do
use Ecto.Repo,
otp_app: :bds,
adapter: Ecto.Adapters.SQLite3
end
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
__MODULE__.RepoConfigBackup.put_env()
on_exit(fn ->
__MODULE__.RepoConfigBackup.restore_env()
end)
:ok
end
test "ensure_schema creates persistence tables in a blank sqlite database" do
temp_db = Path.join(System.tmp_dir!(), "bds-bootstrap-#{System.unique_integer([:positive])}.db")
Application.put_env(:bds, TempRepo,
database: temp_db,
pool_size: 1,
stacktrace: true,
show_sensitive_data_on_connection_error: true
)
start_supervised!(TempRepo)
on_exit(fn ->
File.rm_rf(temp_db)
end)
assert :ok = BDS.RepoBootstrap.ensure_schema(repo: TempRepo)
tables =
Ecto.Adapters.SQL.query!(TempRepo, "SELECT name FROM sqlite_master WHERE type = 'table'", []).rows
|> Enum.map(&hd/1)
assert "projects" in tables
assert "posts" in tables
assert "templates" in tables
end
test "ensure_ready seeds the default project in the app repo" do
BDS.Repo.delete_all(Project)
assert :ok = BDS.RepoBootstrap.ensure_ready(migrate?: false)
assert %Project{id: "default", name: "My Blog", is_active: true} = BDS.Projects.get_active_project()
end
defmodule RepoConfigBackup do
def put_env do
Process.put({__MODULE__, :temp_repo_config}, Application.get_env(:bds, TempRepo))
end
def restore_env do
case Process.get({__MODULE__, :temp_repo_config}) do
nil -> Application.delete_env(:bds, TempRepo)
config -> Application.put_env(:bds, TempRepo, config)
end
end
end
end

View File

@@ -109,6 +109,10 @@ defmodule BDS.UI.ShellTest do
assert html =~ ~s(src="/assets/app.js")
assert html =~ ~s(href="/assets/app.css")
assert html =~ ~s("task_status")
assert html =~ ~s("flag":"🇩🇪")
assert html =~ ~s("projects")
assert html =~ ~s("id":"default")
assert html =~ ~s("name":"My Blog")
end
test "static shell bundle exists for direct browser inspection" do
@@ -144,7 +148,7 @@ defmodule BDS.UI.ShellTest do
assert js =~ "window-titlebar-menu-bar is-hidden"
assert css =~ ".window-titlebar-menu-bar.is-hidden"
assert css =~ "--vscode-statusBar-background: #181818"
assert css =~ "--vscode-statusBar-background: #007acc"
assert css =~ ".status-bar-left,"
assert css =~ "gap: 4px"
assert css =~ "padding: 0 8px"
@@ -155,6 +159,7 @@ defmodule BDS.UI.ShellTest do
assert css =~ ".status-bar-item.offline-badge"
assert js =~ "renderLanguageOptions"
assert js =~ "language.flag || language.code.toUpperCase()"
assert js =~ "status-bar-language-select"
assert js =~ "setUiLanguage"
end
@@ -163,6 +168,7 @@ defmodule BDS.UI.ShellTest do
js = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.js")
assert js =~ "/api/tasks"
assert js =~ "/api/projects"
assert js =~ "/api/commands"
assert js =~ "fetchTaskStatus"
assert js =~ "executeBackendShellCommand"
@@ -179,6 +185,24 @@ defmodule BDS.UI.ShellTest do
assert js =~ "data-panel-tab=\"git_log\""
end
test "static shell bundle renders a left-side project field with selection and create affordances" do
css = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.css")
js = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.js")
assert js =~ "project-selector-trigger"
assert js =~ "project-dropdown"
assert js =~ "create-project-btn"
assert js =~ "fetchProjects"
assert js =~ "createProject"
assert js =~ "selectProject"
assert js =~ "toggleProjectMenu"
assert js =~ "closeProjectMenu"
assert css =~ ".project-selector-trigger"
assert css =~ ".project-dropdown"
assert css =~ ".create-project-btn"
end
test "static shell bundle binds base shell hotkeys and menu actions to existing shell functionality" do
js = File.read!("/Users/gb/Projects/bDS2/priv/ui/app.js")