Skip to content

Commit

Permalink
Add script section to device UI (#1689)
Browse files Browse the repository at this point in the history
Solves #1681 

Adds a simple section on device page for listing and running support
scripts.

Not too much time spent on the looks since the whole UI is redesigned.
  • Loading branch information
elinol authored Dec 10, 2024
1 parent d721560 commit d0cfc57
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/nerves_hub_web/helpers/authorization.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ defmodule NervesHub.Helpers.Authorization do
def authorized?(:"support_script:create", %OrgUser{role: role}), do: role_check(:manage, role)
def authorized?(:"support_script:update", %OrgUser{role: role}), do: role_check(:manage, role)
def authorized?(:"support_script:delete", %OrgUser{role: role}), do: role_check(:manage, role)
def authorized?(:"support_script:run", %OrgUser{role: role}), do: role_check(:view, role)

defp role_check(required_role, user_role) do
required_role
Expand Down
68 changes: 68 additions & 0 deletions lib/nerves_hub_web/live/devices/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule NervesHubWeb.Live.Devices.Show do
alias NervesHub.Devices.Metrics
alias NervesHub.Devices.UpdatePayload
alias NervesHub.Firmwares
alias NervesHub.Scripts
alias NervesHub.Tracker

alias NervesHubWeb.Components.AuditLogFeed
Expand All @@ -20,6 +21,8 @@ defmodule NervesHubWeb.Live.Devices.Show do

alias Phoenix.Socket.Broadcast

@running_script_placeholder "Running Script.."

def mount(%{"device_identifier" => device_identifier}, _session, socket) do
%{org: org, product: product} = socket.assigns

Expand All @@ -44,6 +47,7 @@ defmodule NervesHubWeb.Live.Devices.Show do
|> assign(:alarms, Alarms.get_current_alarms_for_device(device))
|> assign(:extension_overrides, extension_overrides(device, product))
|> assign(:latest_metrics, Metrics.get_latest_metric_set(device.id))
|> assign(:scripts, scripts_with_output(product))
|> assign_metadata()
|> schedule_health_check_timer()
|> assign(:fwup_progress, nil)
Expand Down Expand Up @@ -316,6 +320,63 @@ defmodule NervesHubWeb.Live.Devices.Show do
end
end

def handle_event(
"run-script",
%{"idx" => index},
%{assigns: %{device: device, scripts: scripts, org_user: org_user}} = socket
) do
authorized!(:"support_script:run", org_user)

{script, idx} = Enum.at(scripts, String.to_integer(index))

socket
|> assign(:scripts, update_script_output(scripts, idx, @running_script_placeholder))
|> start_async({:run_script, idx}, fn -> Scripts.Runner.send(device, script) end)
|> noreply()
end

def handle_event(
"clear-script-output",
%{"idx" => index},
%{assigns: %{scripts: scripts}} = socket
) do
socket
|> assign(:scripts, update_script_output(scripts, String.to_integer(index), nil))
|> noreply()
end

def handle_async(
{:run_script, index},
result,
%{assigns: %{scripts: scripts}} = socket
) do
output =
case result do
{:ok, output} ->
output

e ->
inspect(e)
end

socket
|> assign(:scripts, update_script_output(scripts, index, output))
|> noreply()
end

defp scripts_with_output(product) do
product
|> Scripts.all_by_product()
|> Enum.map(&Map.put(&1, :output, nil))
|> Enum.with_index()
end

defp update_script_output(scripts, index, output) do
List.update_at(scripts, index, fn {script, idx} ->
{%{script | output: output}, idx}
end)
end

defp device_connection(%{device_connections: [connection]}), do: connection
defp device_connection(_), do: nil

Expand Down Expand Up @@ -385,4 +446,11 @@ defmodule NervesHubWeb.Live.Devices.Show do
end)
|> Enum.map(&elem(&1, 0))
end

defp running_script_placeholder(), do: @running_script_placeholder

defp script_button_text(output) when output == @running_script_placeholder or is_nil(output),
do: "Run"

defp script_button_text(_), do: "Close"
end
23 changes: 23 additions & 0 deletions lib/nerves_hub_web/live/devices/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,29 @@
</div>
<% end %>
</div>

<div :if={@scripts != []}>
<h3 class="mb-2">Support Scripts</h3>

<div class="display-box">
<div :for={{script, idx} <- @scripts} class="mb-2 pb-2 border-bottom border-dark">
<div class="flex-row align-items-center justify-content-between">
<div><%= script.name %></div>
<button class="btn btn-secondary" disabled={script.output == running_script_placeholder()} phx-click={if script.output, do: "clear-script-output", else: "run-script"} phx-value-idx={idx}>
<%= script_button_text(script.output) %>
</button>
</div>
<div :if={script.output} class="mt-2">
<code class="alarms-description color-white wb-ba ff-m"><%= script.output %></code>
</div>
</div>
<div class="text-right">
<.link navigate={~p"/org/#{@org.name}/#{@product.name}/scripts"}>
Add and edit scripts
</.link>
</div>
</div>
</div>
</div>

<div class="col-lg-6">
Expand Down
29 changes: 29 additions & 0 deletions test/nerves_hub_web/live/devices/show_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,35 @@ defmodule NervesHubWeb.Live.Devices.ShowTest do
end
end

describe "support scripts" do
test "no scripts available", %{
conn: conn,
org: org,
product: product,
device: device
} do
conn
|> visit("/org/#{org.name}/#{product.name}/devices/#{device.identifier}")
|> refute_has("h3", text: "Support Scripts")
end

test "list scripts", %{
conn: conn,
org: org,
product: product,
device: device
} do
{:ok, _command} =
NervesHub.Scripts.create(product, %{name: "MOTD", text: "NervesMOTD.print()"})

conn
|> visit("/org/#{org.name}/#{product.name}/devices/#{device.identifier}")
|> assert_has("h3", text: "Support Scripts")
|> assert_has("div", text: "MOTD")
|> assert_has("button", text: "Run")
end
end

def device_show_path(%{device: device, org: org, product: product}) do
~p"/org/#{org.name}/#{product.name}/devices/#{device.identifier}"
end
Expand Down

0 comments on commit d0cfc57

Please sign in to comment.