Skip to content

Commit

Permalink
Bulk move devices to deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
nshoes committed Dec 27, 2024
1 parent 646235b commit aaffb32
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 6 deletions.
6 changes: 6 additions & 0 deletions lib/nerves_hub/devices.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,12 @@ defmodule NervesHub.Devices do
update_device_with_audit(device, params, user, description)
end

@spec move_many_to_deployment([integer()], integer()) :: {integer(), nil | [term()]}
def move_many_to_deployment(device_ids, deployment_id) do
from(d in Device, where: d.id in ^device_ids)
|> Repo.update_all(set: [deployment_id: deployment_id])
end

@spec move_many([Device.t()], Product.t(), User.t()) :: %{
ok: [Device.t()],
error: [{Ecto.Multi.name(), any()}]
Expand Down
2 changes: 2 additions & 0 deletions lib/nerves_hub/products/product.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule NervesHub.Products.Product do

alias NervesHub.Accounts.Org
alias NervesHub.Archives.Archive
alias NervesHub.Deployments.Deployment
alias NervesHub.Scripts.Script
alias NervesHub.Devices.CACertificate
alias NervesHub.Devices.Device
Expand All @@ -22,6 +23,7 @@ defmodule NervesHub.Products.Product do
has_many(:jitp, CACertificate.JITP)
has_many(:archives, Archive)
has_many(:scripts, Script)
has_many(:deployments, Deployment)

has_many(:shared_secret_auths, SharedSecretAuth,
preload_order: [desc: :deactivated_at, asc: :id]
Expand Down
40 changes: 37 additions & 3 deletions lib/nerves_hub_web/live/devices/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule NervesHubWeb.Live.Devices.Index do
alias NervesHub.Firmwares
alias NervesHub.Products.Product
alias NervesHub.Tracker
alias NervesHub.Repo

alias Phoenix.Socket.Broadcast
alias Phoenix.LiveView.JS
Expand Down Expand Up @@ -73,8 +74,8 @@ defmodule NervesHubWeb.Live.Devices.Index do
total_pages: :integer
}

def mount(_params, _session, socket) do
%{product: product} = socket.assigns
def mount(_params, _session, %{assigns: %{product: product}} = socket) do
product = Repo.preload(product, :deployments)

socket
|> page_title("Devices - #{product.name}")
Expand All @@ -93,6 +94,8 @@ defmodule NervesHubWeb.Live.Devices.Index do
|> assign(:total_entries, 0)
|> assign(:current_alarms, Alarms.get_current_alarm_types(product.id))
|> assign(:metrics_keys, Metrics.default_metrics())
|> assign(:deployments, product.deployments)
|> assign(:target_deployment, nil)
|> subscribe_and_refresh_device_list_timer()
|> ok()
end
Expand Down Expand Up @@ -272,7 +275,18 @@ defmodule NervesHubWeb.Live.Devices.Index do
{:noreply, assign(socket, target_product: target)}
end

def handle_event("move-devices", _, socket) do
def handle_event("target-deployment", %{"deployment" => ""}, socket) do
{:noreply, assign(socket, target_deployment: nil)}
end

def handle_event("target-deployment", %{"deployment" => deployment_id}, socket) do
deployment =
Enum.find(socket.assigns.deployments, &(&1.id == String.to_integer(deployment_id)))

{:noreply, assign(socket, target_deployment: deployment)}
end

def handle_event("move-devices-product", _, socket) do
%{ok: successfuls} =
Devices.get_devices_by_id(socket.assigns.selected_devices)
|> Devices.move_many(socket.assigns.target_product, socket.assigns.user)
Expand All @@ -289,6 +303,26 @@ defmodule NervesHubWeb.Live.Devices.Index do
{:noreply, socket}
end

def handle_event(
"move-devices-deployment",
_,
%{
assigns: %{
selected_devices: selected_devices,
target_deployment: target_deployment
}
} = socket
) do
_ = Devices.move_many_to_deployment(selected_devices, target_deployment.id)

socket =
socket
|> assign(:target_deployment, nil)
|> assign_display_devices()

{:noreply, socket}
end

def handle_event("disable-updates-for-devices", _, socket) do
%{ok: _successfuls} =
Devices.get_devices_by_id(socket.assigns.selected_devices)
Expand Down
30 changes: 27 additions & 3 deletions lib/nerves_hub_web/live/devices/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@
</div>

<div class="row mt-2">
<form id="move" class="col-lg-6" phx-change="target-product" phx-submit="move-devices">
<label for="move_to">Move device(s) to:</label>
<form id="move-product" class="col-lg-4" phx-change="target-product" phx-submit="move-devices-product">
<label for="move_to">Move device(s) to product:</label>
<div class="flex-row align-items-center">
<div class="flex-grow pos-rel">
<select name="product" id="move_to" class="form-control">
Expand All @@ -216,7 +216,7 @@
</div>
</form>

<form id="bulk-tag-input" class="col-lg-6" phx-submit="tag-devices" phx-change="validate-tags">
<form id="bulk-tag-input" class="col-lg-4" phx-submit="tag-devices" phx-change="validate-tags">
<label for="input_set_tags">Set tag(s) to:</label>
<div class="flex-row align-items-center">
<div class="flex-grow">
Expand All @@ -233,6 +233,30 @@
</div>
<div class={if @valid_tags, do: "hidden"}><span class="has-error"> Tags Cannot Contain Spaces </span></div>
</form>

<form id="move-deployment" class="col-lg-4" phx-change="target-deployment" phx-submit="move-devices-deployment">
<label for="move_to">Move device(s) to deployment:</label>
<div class="flex-row align-items-center">
<div class="flex-grow pos-rel">
<select name="deployment" id="move_to" class="form-control">
<option value=""></option>
<%= for deployment <- @deployments do %>
<option value={deployment.id} {if @target_deployment && @target_deployment.id == deployment.id, do: [selected: true], else: []}><%= deployment.name %></option>
<% end %>
</select>
<div class="select-icon"></div>
</div>

<button
class="btn btn-outline-light btn-action btn-primary ml-1"
type="submit"
data-confirm={"This will move all selected devices to #{@target_deployment && @target_deployment.name}. Continue?"}
{unless @target_deployment, do: [disabled: true], else: []}
>
Move
</button>
</div>
</form>
</div>

<div class="row mt-2">
Expand Down
25 changes: 25 additions & 0 deletions test/nerves_hub_web/live/devices/index_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule NervesHubWeb.Live.Devices.IndexTest do
alias NervesHub.Devices
alias NervesHub.Fixtures
alias NervesHubWeb.Endpoint
alias NervesHub.Repo

setup %{fixture: %{device: device}} do
Endpoint.subscribe("device:#{device.id}")
Expand Down Expand Up @@ -278,6 +279,30 @@ defmodule NervesHubWeb.Live.Devices.IndexTest do
|> click_button("Set")
|> assert_has("span", text: "moussaka")
end

test "change deployment", %{conn: conn, fixture: fixture} do

Check failure on line 283 in test/nerves_hub_web/live/devices/index_test.exs

View workflow job for this annotation

GitHub Actions / compile-and-test

test bulk actions change deployment (NervesHubWeb.Live.Devices.IndexTest)
%{device: device, org: org, product: product, firmware: firmware, deployment: deployment} =
fixture

device2 = Fixtures.device_fixture(org, product, firmware)

refute device.deployment_id
refute device2.deployment_id

conn
|> visit("/org/#{org.name}/#{product.name}/devices")
|> unwrap(fn view ->
render_change(view, "select-all", %{"id" => device.id})
end)
|> assert_has("span", text: "2 selected")
|> unwrap(fn view ->
render_change(view, "target-deployment", %{"deployment" => to_string(deployment.id)})
end)
|> click_button("Move")

assert Repo.reload(device) |> Map.get(:deployment_id)
assert Repo.reload(device2) |> Map.get(:deployment_id)
end
end

def device_index_path(%{org: org, product: product}) do
Expand Down

0 comments on commit aaffb32

Please sign in to comment.