fix: issue #20 cmd-J panel tab strip visibility and output panel parity

This commit is contained in:
2026-07-17 20:51:42 +02:00
parent 6c9dd9605b
commit dd53ca3fbc
28 changed files with 1451 additions and 666 deletions

View File

@@ -129,6 +129,31 @@ defmodule BDS.Desktop.AutomationTest do
assert automation_process_counts() == baseline
end
@tag timeout: 120_000
test "cmd-J panel tab strip is visible and switches between tasks and output (issue #20)" do
{:ok, session} = Automation.start_session()
on_exit(fn ->
Automation.stop_session(session)
end)
assert :ok = Automation.press(session, "Meta+J")
snapshot = await(session, & &1.panel_visible)
assert snapshot.panel_visible == true
# The tab strip must offer both tabs and be tall enough to actually see
# and hit them — issue #20 was the strip collapsing to an unusable sliver.
assert "Tasks" in snapshot.panel_tab_labels
assert "Output" in snapshot.panel_tab_labels
assert snapshot.panel_tabs_height >= 20
assert :ok = Automation.click(session, "button[phx-value-tab='output']")
snapshot = await(session, &(&1.panel_active_tab == "Output"))
assert snapshot.panel_active_tab == "Output"
end
@tag timeout: 120_000
test "automation dispatches native menu actions into the liveview shell" do
{:ok, session} = Automation.start_session()

View File

@@ -907,6 +907,120 @@ defmodule BDS.Desktop.ShellLiveTest do
assert html =~ ~s(data-tab-id="#{created_post.id}")
end
test "tasks panel shows a cancel button for running tasks and cancels them" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
{:ok, task} =
BDS.Tasks.submit_task("Long Running Task", fn _report ->
receive do
:finish -> :ok
after
30_000 -> :ok
end
end)
send(view.pid, :refresh_task_status)
html = render_click(view, "select_panel_tab", %{"tab" => "tasks"})
assert html =~ "Long Running Task"
assert html =~ ~s(data-testid="cancel-task-button")
view
|> element(~s{[data-testid="cancel-task-button"]})
|> render_click()
assert Enum.find(BDS.Tasks.list_tasks(), &(&1.id == task.id)).status == :cancelled
end
test "tasks panel groups tasks by group_id and toggles the group collapsed" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
blocking = fn _report ->
receive do
:finish -> :ok
after
30_000 -> :ok
end
end
{:ok, _t1} = BDS.Tasks.submit_task("First Grouped", blocking, %{group_id: "grp", group_name: "Batch"})
{:ok, _t2} = BDS.Tasks.submit_task("Second Grouped", blocking, %{group_id: "grp", group_name: "Batch"})
send(view.pid, :refresh_task_status)
html = render_click(view, "select_panel_tab", %{"tab" => "tasks"})
# One group row for both tasks, expanded by default (task names also
# appear in the status bar, hence the <strong> row scoping)
assert html =~ "Batch (2)"
assert html =~ "<strong>First Grouped</strong>"
assert html =~ "<strong>Second Grouped</strong>"
html = render_click(view, "toggle_task_group", %{"group" => "grp"})
assert html =~ "Batch (2)"
refute html =~ "<strong>First Grouped</strong>"
refute html =~ "<strong>Second Grouped</strong>"
html = render_click(view, "toggle_task_group", %{"group" => "grp"})
assert html =~ "<strong>First Grouped</strong>"
assert html =~ "<strong>Second Grouped</strong>"
end
test "output panel copy button pushes the full log text to the clipboard" do
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
send(view.pid, {:editor_output, "First", "line one", nil, "info"})
send(view.pid, {:editor_output, "Second", "line two", nil, "error"})
html = render_click(view, "select_panel_tab", %{"tab" => "output"})
assert html =~ ~s(data-testid="copy-output-button")
view
|> element(~s{[data-testid="copy-output-button"]})
|> render_click()
# Chronological order (oldest first), entries joined by a blank line.
assert_push_event(view, "clipboard", %{text: "line one\n\nline two"})
end
test "blogmark transform output lands in the output panel and auto-opens it", %{
project: project
} do
{:ok, _script} =
Scripts.create_and_publish_script(%{
project_id: project.id,
title: "Logging Transform",
kind: :transform,
entrypoint: "main",
content:
"function main(data, ctx) bds.app.log('transform ran') print('still ran') return data end"
})
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
url =
"bds2://new-post?title=" <>
URI.encode_www_form("Logged Blogmark") <>
"&url=" <> URI.encode_www_form("https://example.com/logged")
send(view.pid, {:blogmark_deep_link, url})
_html = render(view)
assigns = :sys.get_state(view.pid).socket.assigns
messages = Enum.map(assigns.output_entries, & &1.message)
assert "transform ran" in messages
assert "still ran" in messages
# Like the old app: noteworthy script output opens the panel on Output.
assert assigns.workbench.panel.visible == true
assert assigns.workbench.panel.active_tab == :output
end
test "blogmark deep link with a project_id switches to that project and imports there",
%{project: active} do
{:ok, other} =
@@ -6052,6 +6166,38 @@ defmodule BDS.Desktop.ShellLiveTest do
assert reloaded.version == 1
end
test "script editor run streams print and bds.app.log output to the output panel", %{
project: project
} do
{:ok, script} =
Scripts.create_script(%{
project_id: project.id,
title: "Output Test",
kind: :utility,
content:
"function main() print('from-print') bds.app.log('from-log') return 'done' end"
})
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
render_click(view, "pin_sidebar_item", %{
"route" => "scripts",
"id" => script.id,
"title" => script.title,
"subtitle" => "draft"
})
view
|> element(".scripts-run-button")
|> render_click()
entries = :sys.get_state(view.pid).socket.assigns.output_entries
messages = Enum.map(entries, & &1.message)
assert "from-print" in messages
assert "from-log" in messages
end
test "script editor check syntax validates lua content without saving", %{project: project} do
{:ok, script} =
Scripts.create_script(%{