From 4e991247e16c3e28ef0c3ba586e04cc40f02ae67 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sun, 26 Apr 2026 22:17:06 +0200 Subject: [PATCH] fix: fixed order in sidebars --- lib/bds/desktop/shell_live.ex | 5 - lib/bds/ui/sidebar.ex | 4 +- test/bds/desktop/shell_live_test.exs | 40 ++++++-- test/bds/ui/sidebar_test.exs | 142 +++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 test/bds/ui/sidebar_test.exs diff --git a/lib/bds/desktop/shell_live.ex b/lib/bds/desktop/shell_live.ex index eb15dae..3be8d6d 100644 --- a/lib/bds/desktop/shell_live.ex +++ b/lib/bds/desktop/shell_live.ex @@ -1388,11 +1388,6 @@ defmodule BDS.Desktop.ShellLive do socket |> append_output_entry(translated("sidebar.importMedia"), message, nil, "error") |> reload_shell(socket.assigns.workbench) - - {:error, reason} -> - socket - |> append_output_entry(translated("sidebar.importMedia"), inspect(reason), nil, "error") - |> reload_shell(socket.assigns.workbench) end end diff --git a/lib/bds/ui/sidebar.ex b/lib/bds/ui/sidebar.ex index 01fce3e..7109a3b 100644 --- a/lib/bds/ui/sidebar.ex +++ b/lib/bds/ui/sidebar.ex @@ -297,7 +297,7 @@ defmodule BDS.UI.Sidebar do Repo.all( from post in Post, where: post.project_id == ^project_id, - order_by: [desc: post.updated_at, desc: post.created_at], + order_by: [desc: post.created_at], select: %{ id: post.id, title: post.title, @@ -327,7 +327,7 @@ defmodule BDS.UI.Sidebar do Repo.all( from media in Media, where: media.project_id == ^project_id, - order_by: [desc: media.updated_at, desc: media.created_at], + order_by: [desc: media.created_at], select: %{ id: media.id, title: media.title, diff --git a/test/bds/desktop/shell_live_test.exs b/test/bds/desktop/shell_live_test.exs index 9e30396..c435980 100644 --- a/test/bds/desktop/shell_live_test.exs +++ b/test/bds/desktop/shell_live_test.exs @@ -64,21 +64,21 @@ defmodule BDS.Desktop.ShellLiveTest do assert html =~ ~s(data-sidebar-action="media") assert html =~ ~s(data-testid="sidebar-filter-toggle") - _html = + html = view |> element("[data-testid='activity-button'][data-view='scripts']") |> render_click() assert html =~ ~s(data-sidebar-action="script") - _html = + html = view |> element("[data-testid='activity-button'][data-view='templates']") |> render_click() assert html =~ ~s(data-sidebar-action="template") - _html = + html = view |> element("[data-testid='activity-button'][data-view='import']") |> render_click() @@ -106,7 +106,7 @@ defmodule BDS.Desktop.ShellLiveTest do assert created_post.content == "" refute html =~ ~s(data-tab-type="post") - html = render_click(view, "select_view", %{"view" => "scripts"}) + _html = render_click(view, "select_view", %{"view" => "scripts"}) html = view @@ -123,7 +123,7 @@ defmodule BDS.Desktop.ShellLiveTest do assert html =~ ~s(data-tab-type="scripts") assert html =~ ~s(data-tab-id="#{created_script.id}") - html = render_click(view, "select_view", %{"view" => "templates"}) + _html = render_click(view, "select_view", %{"view" => "templates"}) html = view @@ -139,9 +139,12 @@ defmodule BDS.Desktop.ShellLiveTest do assert html =~ ~s(data-tab-type="templates") assert html =~ ~s(data-tab-id="#{created_template.id}") - html = render_click(view, "select_view", %{"view" => "import"}) + _html = render_click(view, "select_view", %{"view" => "import"}) - render_click(view, "select_view", %{"view" => "scripts"}) + html = + view + |> element("[data-testid='sidebar-create-action'][data-sidebar-action='import']") + |> render_click() assert Repo.aggregate(ImportDefinitions.ImportDefinition, :count, :id) == import_count_before + 1 @@ -164,11 +167,30 @@ defmodule BDS.Desktop.ShellLiveTest do assert html =~ ~s(data-view="media") assert html =~ ~s(aria-label="Posts") - render_click(view, "select_view", %{"view" => "templates"}) + html = render_click(view, "select_view", %{"view" => "templates"}) + + assert html =~ ~s(data-view="templates") + assert html =~ ~s(data-active="true") + assert html =~ ~s(aria-label="Templates") + + html = + view + |> element("[data-testid='toggle-sidebar']") + |> render_click() assert html =~ ~s(class="sidebar-shell is-hidden") - render_click(view, "select_view", %{"view" => "import"}) + html = + view + |> element("[data-testid='toggle-sidebar']") + |> render_click() + + refute html =~ ~s(class="sidebar-shell is-hidden") + + html = + view + |> element("[data-testid='toggle-panel']") + |> render_click() assert html =~ ~s(data-region="panel") refute html =~ ~s(class="panel-shell is-hidden") diff --git a/test/bds/ui/sidebar_test.exs b/test/bds/ui/sidebar_test.exs new file mode 100644 index 0000000..ead33d4 --- /dev/null +++ b/test/bds/ui/sidebar_test.exs @@ -0,0 +1,142 @@ +defmodule BDS.UI.SidebarTest do + use ExUnit.Case, async: false + + import Ecto.Query + + alias BDS.AI + alias BDS.ImportDefinitions + alias BDS.Media + alias BDS.Posts + alias BDS.Posts.Post + alias BDS.Projects + alias BDS.Repo + alias BDS.Scripts + alias BDS.Templates + alias BDS.UI.Sidebar + + setup do + :ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo) + + temp_dir = Path.join(System.tmp_dir!(), "bds-sidebar-#{System.unique_integer([:positive])}") + File.mkdir_p!(temp_dir) + + on_exit(fn -> File.rm_rf(temp_dir) end) + + {:ok, project} = Projects.create_project(%{name: "Sidebar", data_path: temp_dir}) + %{project: project, temp_dir: temp_dir} + end + + test "database-backed sidebar views follow the old app ordering keys", %{project: project, temp_dir: temp_dir} do + assert {:ok, draft_old} = Posts.create_post(%{project_id: project.id, title: "Draft Old"}) + assert {:ok, draft_new} = Posts.create_post(%{project_id: project.id, title: "Draft New"}) + assert {:ok, published_old} = Posts.create_post(%{project_id: project.id, title: "Published Old"}) + assert {:ok, published_new} = Posts.create_post(%{project_id: project.id, title: "Published New"}) + assert {:ok, archived_old} = Posts.create_post(%{project_id: project.id, title: "Archived Old"}) + assert {:ok, archived_new} = Posts.create_post(%{project_id: project.id, title: "Archived New"}) + + update_post_sidebar_row(draft_old.id, created_at: 1_000, updated_at: 9_000) + update_post_sidebar_row(draft_new.id, created_at: 2_000, updated_at: 1_000) + + update_post_sidebar_row( + published_old.id, + status: :published, + created_at: 3_000, + updated_at: 9_000, + published_at: 3_000, + file_path: "posts/published-old.md" + ) + + update_post_sidebar_row( + published_new.id, + status: :published, + created_at: 4_000, + updated_at: 1_000, + published_at: 4_000, + file_path: "posts/published-new.md" + ) + + update_post_sidebar_row(archived_old.id, status: :archived, created_at: 5_000, updated_at: 9_000) + update_post_sidebar_row(archived_new.id, status: :archived, created_at: 6_000, updated_at: 1_000) + + old_media_path = Path.join(temp_dir, "old-media.txt") + new_media_path = Path.join(temp_dir, "new-media.txt") + File.write!(old_media_path, "old media") + File.write!(new_media_path, "new media") + + assert {:ok, old_media} = Media.import_media(%{project_id: project.id, source_path: old_media_path, title: "Old Media"}) + assert {:ok, new_media} = Media.import_media(%{project_id: project.id, source_path: new_media_path, title: "New Media"}) + update_media_sidebar_row(old_media.id, created_at: 7_000, updated_at: 9_000) + update_media_sidebar_row(new_media.id, created_at: 8_000, updated_at: 1_000) + + assert {:ok, old_script} = Scripts.create_script(%{project_id: project.id, title: "Old Script", kind: :utility, content: "print('old')", entrypoint: "main"}) + assert {:ok, new_script} = Scripts.create_script(%{project_id: project.id, title: "New Script", kind: :utility, content: "print('new')", entrypoint: "main"}) + update_script_sidebar_row(old_script.id, 9_000) + update_script_sidebar_row(new_script.id, 10_000) + + assert {:ok, old_template} = Templates.create_template(%{project_id: project.id, title: "Old Template", kind: :post, content: "old"}) + assert {:ok, new_template} = Templates.create_template(%{project_id: project.id, title: "New Template", kind: :post, content: "new"}) + update_template_sidebar_row(old_template.id, 11_000) + update_template_sidebar_row(new_template.id, 12_000) + + assert {:ok, old_chat} = AI.start_chat(%{title: "Old Chat"}) + assert {:ok, new_chat} = AI.start_chat(%{title: "New Chat"}) + update_chat_sidebar_row(old_chat.id, 13_000) + update_chat_sidebar_row(new_chat.id, 14_000) + + assert {:ok, old_definition} = ImportDefinitions.create_definition(%{project_id: project.id, name: "Old Import"}) + assert {:ok, new_definition} = ImportDefinitions.create_definition(%{project_id: project.id, name: "New Import"}) + update_import_sidebar_row(old_definition.id, 15_000) + update_import_sidebar_row(new_definition.id, 16_000) + + posts_view = Sidebar.view(project.id, "posts") + assert titles_in_section(posts_view, "Drafts") == ["Draft New", "Draft Old"] + assert titles_in_section(posts_view, "Published") == ["Published New", "Published Old"] + assert titles_in_section(posts_view, "Archived") == ["Archived New", "Archived Old"] + + media_view = Sidebar.view(project.id, "media") + assert Enum.map(media_view.items, & &1.title) == ["New Media", "Old Media"] + + scripts_view = Sidebar.view(project.id, "scripts") + assert Enum.map(scripts_view.items, & &1.title) == ["New Script", "Old Script"] + + templates_view = Sidebar.view(project.id, "templates") + assert Enum.map(templates_view.items, & &1.title) == ["New Template", "Old Template"] + + chat_view = Sidebar.view(project.id, "chat") + assert Enum.map(chat_view.items, & &1.title) == ["New Chat", "Old Chat"] + + import_view = Sidebar.view(project.id, "import") + assert Enum.map(import_view.items, & &1.title) == ["New Import", "Old Import"] + end + + defp titles_in_section(view, title) do + view.sections + |> Enum.find(&(&1.title == title)) + |> Map.fetch!(:items) + |> Enum.map(& &1.title) + end + + defp update_post_sidebar_row(post_id, updates) do + Repo.update_all(from(post in Post, where: post.id == ^post_id), set: updates) + end + + defp update_media_sidebar_row(media_id, updates) do + Repo.update_all(from(media in BDS.Media.Media, where: media.id == ^media_id), set: updates) + end + + defp update_script_sidebar_row(script_id, updated_at) do + Repo.update_all(from(script in BDS.Scripts.Script, where: script.id == ^script_id), set: [updated_at: updated_at]) + end + + defp update_template_sidebar_row(template_id, updated_at) do + Repo.update_all(from(template in BDS.Templates.Template, where: template.id == ^template_id), set: [updated_at: updated_at]) + end + + defp update_chat_sidebar_row(conversation_id, updated_at) do + Repo.update_all(from(conversation in BDS.AI.ChatConversation, where: conversation.id == ^conversation_id), set: [updated_at: updated_at]) + end + + defp update_import_sidebar_row(definition_id, updated_at) do + Repo.update_all(from(definition in BDS.ImportDefinitions.ImportDefinition, where: definition.id == ^definition_id), set: [updated_at: updated_at]) + end +end