feat: adding "+" buttons to sidebar titles
This commit is contained in:
@@ -5,7 +5,7 @@ defmodule BDS.Desktop.ShellLive do
|
||||
|
||||
import Phoenix.HTML
|
||||
|
||||
alias BDS.Desktop.{FolderPicker, Overlay, ShellCommands, ShellData}
|
||||
alias BDS.Desktop.{FilePicker, FolderPicker, Overlay, ShellCommands, ShellData}
|
||||
alias BDS.Desktop.ShellLive.{ChatEditor, CodeEntityEditor, MediaEditor, MiscEditor, SettingsEditor, TagsEditor}
|
||||
alias BDS.Desktop.ShellLive.OverlayComponents, as: ShellOverlayComponents
|
||||
alias BDS.Desktop.ShellLive.PostEditor
|
||||
@@ -13,11 +13,13 @@ defmodule BDS.Desktop.ShellLive do
|
||||
alias BDS.Desktop.ShellLive.SidebarState, as: ShellSidebarState
|
||||
alias BDS.Desktop.MenuBar, as: DesktopMenuBar
|
||||
alias BDS.Git
|
||||
alias BDS.ImportDefinitions
|
||||
alias BDS.Media.Media
|
||||
alias BDS.PostLinks
|
||||
alias BDS.Posts.Post
|
||||
alias BDS.Projects
|
||||
alias BDS.Repo
|
||||
alias BDS.Scripts
|
||||
alias BDS.Templates
|
||||
alias BDS.UI.{Commands, MenuBar, Registry, Session, Workbench}
|
||||
|
||||
@@ -282,6 +284,10 @@ defmodule BDS.Desktop.ShellLive do
|
||||
|> reload_shell(socket.assigns.workbench)}
|
||||
end
|
||||
|
||||
def handle_event("create_sidebar_item", %{"kind" => kind}, socket) do
|
||||
{:noreply, create_sidebar_item(socket, kind)}
|
||||
end
|
||||
|
||||
def handle_event("shortcut", params, socket) do
|
||||
if ignore_shortcut?(params) do
|
||||
{:noreply, socket}
|
||||
@@ -1345,6 +1351,102 @@ defmodule BDS.Desktop.ShellLive do
|
||||
Map.get(params, :tag) in ["INPUT", "TEXTAREA", "SELECT"]
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, kind) do
|
||||
case socket.assigns.projects.active_project_id do
|
||||
project_id when is_binary(project_id) -> create_sidebar_item(socket, project_id, kind)
|
||||
_other -> reload_shell(socket, socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, project_id, "post") do
|
||||
case BDS.Posts.create_post(%{project_id: project_id, title: "", content: "", tags: [], categories: []}) do
|
||||
{:ok, _post} -> reload_shell(socket, socket.assigns.workbench)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output_entry(translated("sidebar.newPost"), inspect(reason), nil, "error")
|
||||
|> reload_shell(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, project_id, "media") do
|
||||
case FilePicker.choose_file(translated("sidebar.importMedia")) do
|
||||
{:ok, source_path} ->
|
||||
case BDS.Media.import_media(%{project_id: project_id, source_path: source_path}) do
|
||||
{:ok, _media} -> reload_shell(socket, socket.assigns.workbench)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output_entry(translated("sidebar.importMedia"), inspect(reason), nil, "error")
|
||||
|> reload_shell(socket.assigns.workbench)
|
||||
end
|
||||
|
||||
:cancel ->
|
||||
reload_shell(socket, socket.assigns.workbench)
|
||||
|
||||
{:error, %{message: message}} ->
|
||||
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
|
||||
|
||||
defp create_sidebar_item(socket, project_id, "script") do
|
||||
case Scripts.create_script(%{
|
||||
project_id: project_id,
|
||||
title: translated("sidebar.scripts.newScript"),
|
||||
kind: :utility,
|
||||
content: "print(\"new script\")",
|
||||
entrypoint: "main",
|
||||
enabled: true
|
||||
}) do
|
||||
{:ok, script} ->
|
||||
open_sidebar_item(socket, %{"route" => "scripts", "id" => script.id, "title" => script.title, "subtitle" => "Automation helpers"}, :pin)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output_entry(translated("sidebar.scripts.newScript"), inspect(reason), nil, "error")
|
||||
|> reload_shell(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, project_id, "template") do
|
||||
case Templates.create_template(%{
|
||||
project_id: project_id,
|
||||
title: translated("sidebar.templates.newTemplate"),
|
||||
kind: :post,
|
||||
content: "",
|
||||
enabled: true
|
||||
}) do
|
||||
{:ok, template} ->
|
||||
open_sidebar_item(socket, %{"route" => "templates", "id" => template.id, "title" => template.title, "subtitle" => "Site rendering"}, :pin)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output_entry(translated("sidebar.templates.newTemplate"), inspect(reason), nil, "error")
|
||||
|> reload_shell(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, project_id, "import") do
|
||||
case ImportDefinitions.create_definition(%{project_id: project_id, name: translated("sidebar.import.newDefinition")}) do
|
||||
{:ok, definition} ->
|
||||
open_sidebar_item(socket, %{"route" => "import", "id" => definition.id, "title" => definition.name, "subtitle" => "Import definitions"}, :pin)
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> append_output_entry(translated("sidebar.import.newDefinition"), inspect(reason), nil, "error")
|
||||
|> reload_shell(socket.assigns.workbench)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_sidebar_item(socket, _project_id, _kind), do: reload_shell(socket, socket.assigns.workbench)
|
||||
|
||||
defp open_sidebar_item(socket, params, intent) do
|
||||
route_atom = sidebar_route_atom(Map.fetch!(params, "route"))
|
||||
tab_id = tab_id_for_route(route_atom, Map.fetch!(params, "id"))
|
||||
@@ -1364,6 +1466,13 @@ defmodule BDS.Desktop.ShellLive do
|
||||
|> reload_shell(workbench)
|
||||
end
|
||||
|
||||
defp sidebar_create_action(:posts), do: %{kind: "post", label: "sidebar.newPost"}
|
||||
defp sidebar_create_action(:media), do: %{kind: "media", label: "sidebar.importMedia"}
|
||||
defp sidebar_create_action(:scripts), do: %{kind: "script", label: "sidebar.scripts.newScript"}
|
||||
defp sidebar_create_action(:templates), do: %{kind: "template", label: "sidebar.templates.newTemplate"}
|
||||
defp sidebar_create_action(:import), do: %{kind: "import", label: "sidebar.import.newDefinition"}
|
||||
defp sidebar_create_action(_view), do: nil
|
||||
|
||||
defp set_page_language(socket, language) do
|
||||
codes = Enum.map(socket.assigns[:supported_ui_languages] || ShellData.supported_ui_languages(), & &1.code)
|
||||
|
||||
|
||||
@@ -164,25 +164,44 @@
|
||||
<div class="sidebar" data-region="sidebar">
|
||||
<div id="sidebar-content" class="sidebar-content sidebar-body" phx-hook="SidebarInteractions">
|
||||
<div class="sidebar-section">
|
||||
<% create_action = sidebar_create_action(@workbench.active_view) %>
|
||||
<div class="sidebar-section-header">
|
||||
<span><%= String.upcase(sidebar_header_label(@sidebar_header)) %></span>
|
||||
<%= if ShellSidebarComponents.filters_enabled?(@sidebar_data) do %>
|
||||
<%= if create_action || ShellSidebarComponents.filters_enabled?(@sidebar_data) do %>
|
||||
<div class="sidebar-actions">
|
||||
<button
|
||||
class={[
|
||||
"sidebar-action",
|
||||
if(ShellSidebarComponents.filters_visible?(@sidebar_data), do: "active")
|
||||
]}
|
||||
data-testid="sidebar-filter-toggle"
|
||||
type="button"
|
||||
phx-click="toggle_sidebar_filters"
|
||||
aria-label={translated(Map.get(@sidebar_data.filters, :toggle_filters_label))}
|
||||
title={translated(Map.get(@sidebar_data.filters, :toggle_filters_label))}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M6 12v-1h4v1H6zM4 8v-1h8v1H4zm-2-4v-1h12v1H2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<%= if ShellSidebarComponents.filters_enabled?(@sidebar_data) do %>
|
||||
<button
|
||||
class={[
|
||||
"sidebar-action",
|
||||
if(ShellSidebarComponents.filters_visible?(@sidebar_data), do: "active")
|
||||
]}
|
||||
data-testid="sidebar-filter-toggle"
|
||||
type="button"
|
||||
phx-click="toggle_sidebar_filters"
|
||||
aria-label={translated(Map.get(@sidebar_data.filters, :toggle_filters_label))}
|
||||
title={translated(Map.get(@sidebar_data.filters, :toggle_filters_label))}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M6 12v-1h4v1H6zM4 8v-1h8v1H4zm-2-4v-1h12v1H2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<% end %>
|
||||
<%= if create_action do %>
|
||||
<button
|
||||
class="sidebar-action"
|
||||
data-testid="sidebar-create-action"
|
||||
data-sidebar-action={create_action.kind}
|
||||
type="button"
|
||||
phx-click="create_sidebar_item"
|
||||
phx-value-kind={create_action.kind}
|
||||
aria-label={translated(create_action.label)}
|
||||
title={translated(create_action.label)}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M14 7v1H8v6H7V8H1V7h6V1h1v6h6z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
37
lib/bds/import_definitions.ex
Normal file
37
lib/bds/import_definitions.ex
Normal file
@@ -0,0 +1,37 @@
|
||||
defmodule BDS.ImportDefinitions do
|
||||
@moduledoc false
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias BDS.ImportDefinitions.ImportDefinition
|
||||
alias BDS.Persistence
|
||||
alias BDS.Repo
|
||||
|
||||
def create_definition(attrs) do
|
||||
now = Persistence.now_ms()
|
||||
|
||||
%ImportDefinition{}
|
||||
|> ImportDefinition.changeset(%{
|
||||
id: Ecto.UUID.generate(),
|
||||
project_id: attr(attrs, :project_id),
|
||||
name: attr(attrs, :name) || "",
|
||||
wxr_file_path: attr(attrs, :wxr_file_path),
|
||||
uploads_folder_path: attr(attrs, :uploads_folder_path),
|
||||
last_analysis_result: attr(attrs, :last_analysis_result),
|
||||
created_at: now,
|
||||
updated_at: now
|
||||
})
|
||||
|> Repo.insert()
|
||||
end
|
||||
|
||||
def list_definitions(project_id) do
|
||||
Repo.all(
|
||||
from definition in ImportDefinition,
|
||||
where: definition.project_id == ^project_id,
|
||||
order_by: [desc: definition.updated_at, desc: definition.created_at],
|
||||
select: %{id: definition.id, title: definition.name, updated_at: definition.updated_at}
|
||||
)
|
||||
end
|
||||
|
||||
defp attr(attrs, key), do: Map.get(attrs, key) || Map.get(attrs, Atom.to_string(key))
|
||||
end
|
||||
25
lib/bds/import_definitions/import_definition.ex
Normal file
25
lib/bds/import_definitions/import_definition.ex
Normal file
@@ -0,0 +1,25 @@
|
||||
defmodule BDS.ImportDefinitions.ImportDefinition do
|
||||
@moduledoc false
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
@primary_key {:id, :string, autogenerate: false}
|
||||
|
||||
schema "import_definitions" do
|
||||
field :project_id, :string
|
||||
field :name, :string
|
||||
field :wxr_file_path, :string
|
||||
field :uploads_folder_path, :string
|
||||
field :last_analysis_result, :string
|
||||
field :created_at, :integer
|
||||
field :updated_at, :integer
|
||||
end
|
||||
|
||||
def changeset(definition, attrs) do
|
||||
definition
|
||||
|> cast(attrs, [:id, :project_id, :name, :wxr_file_path, :uploads_folder_path, :last_analysis_result, :created_at, :updated_at])
|
||||
|> validate_required([:id, :project_id, :name, :created_at, :updated_at])
|
||||
end
|
||||
end
|
||||
@@ -4,6 +4,7 @@ defmodule BDS.UI.Sidebar do
|
||||
import Ecto.Query
|
||||
|
||||
alias BDS.AI.ChatConversation
|
||||
alias BDS.ImportDefinitions
|
||||
alias BDS.Media.Media
|
||||
alias BDS.Posts.Post
|
||||
alias BDS.Posts.Translation
|
||||
@@ -26,7 +27,7 @@ defmodule BDS.UI.Sidebar do
|
||||
"templates" => view(project_id, "templates"),
|
||||
"tags" => view(project_id, "tags"),
|
||||
"chat" => view(project_id, "chat"),
|
||||
"import" => entity_list_view("Import", "Import definitions", "import", []),
|
||||
"import" => entity_list_view("Import", "Import definitions", "import", list_import_definitions(project_id)),
|
||||
"git" => git_view(),
|
||||
"settings" => settings_nav_view()
|
||||
}
|
||||
@@ -47,7 +48,7 @@ defmodule BDS.UI.Sidebar do
|
||||
"templates" -> entity_list_view("Templates", "Site rendering", "templates", list_templates(project_id))
|
||||
"tags" -> tags_nav_view(list_tags(project_id))
|
||||
"chat" -> entity_list_view("Chat", "AI conversations", "chat", list_conversations())
|
||||
"import" -> entity_list_view("Import", "Import definitions", "import", [])
|
||||
"import" -> entity_list_view("Import", "Import definitions", "import", list_import_definitions(project_id))
|
||||
"git" -> git_view()
|
||||
"settings" -> settings_nav_view()
|
||||
_other -> empty_view(normalized_view)
|
||||
@@ -359,6 +360,10 @@ defmodule BDS.UI.Sidebar do
|
||||
)
|
||||
end
|
||||
|
||||
defp list_import_definitions(project_id) do
|
||||
ImportDefinitions.list_definitions(project_id)
|
||||
end
|
||||
|
||||
defp list_tags(project_id) do
|
||||
Repo.all(
|
||||
from tag in Tag,
|
||||
|
||||
Reference in New Issue
Block a user