diff --git a/lib/pinchflat_web/components/core_components.ex b/lib/pinchflat_web/components/core_components.ex
index ccdf0b9..58f785c 100644
--- a/lib/pinchflat_web/components/core_components.ex
+++ b/lib/pinchflat_web/components/core_components.ex
@@ -266,6 +266,7 @@ defmodule PinchflatWeb.CoreComponents do
multiple pattern placeholder readonly required rows size step)
slot :inner_block
+ slot :input_append
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
assigns
@@ -424,20 +425,23 @@ defmodule PinchflatWeb.CoreComponents do
<.label for={@id}>
<%= @label %><%= @label_suffix %>
-
+
+
+ <%= render_slot(@input_append) %>
+
<.help :if={@help}><%= if @html_help, do: Phoenix.HTML.raw(@help), else: @help %>
<.error :for={msg <- @errors}><%= msg %>
diff --git a/lib/pinchflat_web/components/custom_components/button_components.ex b/lib/pinchflat_web/components/custom_components/button_components.ex
index a80bb75..61a8ed1 100644
--- a/lib/pinchflat_web/components/custom_components/button_components.ex
+++ b/lib/pinchflat_web/components/custom_components/button_components.ex
@@ -89,4 +89,46 @@ defmodule PinchflatWeb.CustomComponents.ButtonComponents do
"""
end
+
+ @doc """
+ Render a button with an icon. Optionally include a tooltip.
+
+ ## Examples
+
+ <.icon_button icon_name="hero-check" tooltip="Complete" />
+ """
+ attr :icon_name, :string, required: true
+ attr :class, :string, default: ""
+ attr :tooltip, :string, default: nil
+ attr :rest, :global
+
+ def icon_button(assigns) do
+ ~H"""
+
+
+
+
+
+ <%= @tooltip %>
+
+
+ """
+ end
end
diff --git a/lib/pinchflat_web/controllers/settings/setting_html.ex b/lib/pinchflat_web/controllers/settings/setting_html.ex
index 47ad97c..392975d 100644
--- a/lib/pinchflat_web/controllers/settings/setting_html.ex
+++ b/lib/pinchflat_web/controllers/settings/setting_html.ex
@@ -6,6 +6,7 @@ defmodule PinchflatWeb.Settings.SettingHTML do
@doc """
Renders a setting form.
"""
+ attr :conn, Plug.Conn, required: true
attr :changeset, Ecto.Changeset, required: true
attr :action, :string, required: true
diff --git a/lib/pinchflat_web/controllers/settings/setting_html/apprise_server_live.ex b/lib/pinchflat_web/controllers/settings/setting_html/apprise_server_live.ex
new file mode 100644
index 0000000..a482f36
--- /dev/null
+++ b/lib/pinchflat_web/controllers/settings/setting_html/apprise_server_live.ex
@@ -0,0 +1,55 @@
+defmodule Pinchflat.Settings.AppriseServerLive do
+ use PinchflatWeb, :live_view
+
+ alias PinchflatWeb.Settings.SettingHTML
+
+ def render(assigns) do
+ ~H"""
+ <.input
+ type="text"
+ id="setting_apprise_server"
+ name="setting[apprise_server]"
+ value={@value}
+ label="Apprise Server"
+ help={SettingHTML.apprise_server_help()}
+ html_help={true}
+ inputclass="font-mono text-sm mr-4"
+ placeholder="https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}"
+ phx-change="apprise_server_changed"
+ >
+ <:input_append>
+ <.icon_button icon_name={@icon_name} class="h-12 w-12" phx-click="send_apprise_test" tooltip={@tooltip} />
+
+
+ """
+ end
+
+ def mount(_params, session, socket) do
+ new_assigns = %{
+ value: session["value"],
+ icon_name: "hero-paper-airplane",
+ tooltip: "Send Test"
+ }
+
+ {:ok, assign(socket, new_assigns)}
+ end
+
+ def handle_event("send_apprise_test", _params, %{assigns: assigns} = socket) do
+ backend_runner().run([assigns.value], title: "Pinchflat Test", body: "This is a test message from Pinchflat")
+ Process.send_after(self(), :reset_button_icon, 4_000)
+
+ {:noreply, assign(socket, %{icon_name: "hero-check", tooltip: "Sent!"})}
+ end
+
+ def handle_event("apprise_server_changed", %{"setting" => setting}, socket) do
+ {:noreply, assign(socket, %{value: setting["apprise_server"]})}
+ end
+
+ def handle_info(:reset_button_icon, socket) do
+ {:noreply, assign(socket, %{icon_name: "hero-paper-airplane", tooltip: "Send Test"})}
+ end
+
+ defp backend_runner do
+ Application.get_env(:pinchflat, :apprise_runner)
+ end
+end
diff --git a/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex b/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
index 9958c5a..f8e5d7e 100644
--- a/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
+++ b/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
@@ -7,15 +7,13 @@
Notification Settings
- <.input
- field={f[:apprise_server]}
- type="text"
- label="Apprise Server"
- help={apprise_server_help()}
- html_help={true}
- inputclass="font-mono text-sm"
- placeholder="https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}"
- />
+
+ <%= live_render(
+ @conn,
+ Pinchflat.Settings.AppriseServerLive,
+ session: %{"value" => f[:apprise_server].value}
+ ) %>
+
<.button class="mt-10 mb-4 sm:mb-8 w-full sm:w-auto" rounding="rounded-lg">Save Settings
diff --git a/lib/pinchflat_web/controllers/settings/setting_html/show.html.heex b/lib/pinchflat_web/controllers/settings/setting_html/show.html.heex
index abe2938..9921bc9 100644
--- a/lib/pinchflat_web/controllers/settings/setting_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/settings/setting_html/show.html.heex
@@ -7,6 +7,6 @@
- <.setting_form changeset={@changeset} action={~p"/settings"} />
+ <.setting_form conn={@conn} changeset={@changeset} action={~p"/settings"} />
diff --git a/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex b/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
index 8c56d97..b6bfd76 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
+++ b/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
@@ -12,13 +12,7 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
def render(%{records: []} = assigns) do
~H"""
-
+ <.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" />
Nothing Here!
"""
@@ -28,13 +22,7 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
~H"""
-
+ <.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" tooltip="Refresh" />
Showing <%= length(@records) %> of <%= @total_record_count %>
<.table rows={@records} table_class="text-white">
diff --git a/test/pinchflat_web/controllers/settings/apprise_server_live_test.exs b/test/pinchflat_web/controllers/settings/apprise_server_live_test.exs
new file mode 100644
index 0000000..e09265f
--- /dev/null
+++ b/test/pinchflat_web/controllers/settings/apprise_server_live_test.exs
@@ -0,0 +1,70 @@
+defmodule PinchflatWeb.Settings.AppriseServerLiveTest do
+ use PinchflatWeb.ConnCase
+
+ import Mox
+ import Phoenix.LiveViewTest
+
+ alias Pinchflat.Settings.AppriseServerLive
+
+ setup :verify_on_exit!
+
+ describe "initial rendering" do
+ test "renders the input", %{conn: conn} do
+ {:ok, _view, html} = live_isolated(conn, AppriseServerLive, session: create_session(""))
+
+ assert html =~ ~s(input type="text" name="setting[apprise_server]")
+ end
+
+ test "sets the initial value from the session", %{conn: conn} do
+ {:ok, _view, html} = live_isolated(conn, AppriseServerLive, session: create_session("cool-value"))
+
+ assert html =~ ~s(value="cool-value")
+ end
+
+ test "shows a relevant button icon", %{conn: conn} do
+ {:ok, _view, html} = live_isolated(conn, AppriseServerLive, session: create_session(""))
+
+ assert html =~ "hero-paper-airplane"
+ refute html =~ "hero-check"
+ end
+ end
+
+ describe "pressing the button" do
+ setup do
+ stub(AppriseRunnerMock, :run, fn _, _ -> {:ok, ""} end)
+
+ :ok
+ end
+
+ test "sends a test message to the specified server", %{conn: conn} do
+ expect(AppriseRunnerMock, :run, fn servers, args ->
+ assert servers == ["cool-value"]
+ assert args == [title: "Pinchflat Test", body: "This is a test message from Pinchflat"]
+
+ {:ok, ""}
+ end)
+
+ {:ok, view, _html} = live_isolated(conn, AppriseServerLive, session: create_session("cool-value"))
+
+ assert view
+ |> element("button")
+ |> render_click()
+ end
+
+ test "sets the button icon to a checkmark", %{conn: conn} do
+ {:ok, view, _html} = live_isolated(conn, AppriseServerLive, session: create_session("cool-value"))
+
+ result =
+ view
+ |> element("button")
+ |> render_click()
+
+ refute result =~ "hero-paper-airplane"
+ assert result =~ "hero-check"
+ end
+ end
+
+ defp create_session(value) do
+ %{"value" => value}
+ end
+end