- """
- end
-end
diff --git a/lib/nerves_hub_web/components/device_location.ex b/lib/nerves_hub_web/components/device_location.ex
index 0fc5a8569..65a1451c9 100644
--- a/lib/nerves_hub_web/components/device_location.ex
+++ b/lib/nerves_hub_web/components/device_location.ex
@@ -1,7 +1,13 @@
defmodule NervesHubWeb.Components.DeviceLocation do
use NervesHubWeb, :component
+ alias Phoenix.LiveView.JS
+
attr(:location, :any)
+ attr(:enabled_device, :any)
+ attr(:enabled_product, :any)
+ attr(:enable_location_editor, :boolean)
+ attr(:target, :any)
# catch all to add the mapbox token
def render(assigns) when not is_map_key(assigns, :mapbox_access_token) do
@@ -15,92 +21,233 @@ defmodule NervesHubWeb.Components.DeviceLocation do
# mapbox token is nil, maps aren't enabled
def render(%{mapbox_access_token: nil} = assigns) do
~H"""
-
- <.location_header tooltip="The devices location is determined by looking up the request IP of the device using a GeoIP database." />
+
+
+
Location
+
+
+
+
+
+
Device maps haven't been enabled on your platform.
+
Please contact your platform admin.
+
+
+
+ """
+ end
-
- Device maps haven't been enabled on your platform.
+ # disabled in product settings
+ def render(%{enabled_product: false} = assigns) do
+ ~H"""
+
+
+
Location
-
- Please contact your platform admin.
+
+
+
+
+
Device maps have been disabled in your product settings.
+
To enable this feature, please contact your product admin.
+
"""
end
- # location information is nil, geo location might not be enabled
- def render(%{location: nil}) do
- render(%{location: %{}})
+ # disabled in device settings
+ def render(%{enabled_device: false} = assigns) do
+ ~H"""
+
+
+
Location
+
+
+
+
+
+
Device maps have been disabled for this device.
+
To enable this feature, please contact your product admin.
+
+
+
+ """
end
- # location information is empty, geo location might not be enabled
- def render(%{location: location} = assigns)
- when map_size(location) == 0 do
+ # yay, we have a location and map key, lets display a map
+ def render(%{enable_location_editor: true} = assigns) do
~H"""
-
- <.location_header tooltip="The devices location is announced by the device after it connects." />
+
+
+
Location
+
+ Please select the devices location.
+
+
-
- No location information found.
+
-
- Please check if the Geo extension has been included in your firmware.
+
+
"""
end
- # the IP address was a reserved IP (https://en.wikipedia.org/wiki/Reserved_IP_addresses)
- # maps can't be shown for reserved IPs
+ # location information is nil or empty, geo location might not be enabled
+ def render(%{location: location} = assigns)
+ when is_nil(location) or map_size(location) == 0 do
+ ~H"""
+
+
+
Location
+
The devices location is announced by the device after it connects.
+
+
+
+
+
+
No location information found.
+
Please check if the Geo extension has been included in your firmware.
+
+ <.button phx-click="enable-location-editor" phx-target={@target}>Manually set the location
+
+
+
+
+ """
+ end
+
+ # TODO: is this an API we need to document in link?
def render(%{location: %{"error_code" => _} = location}) do
assigns = %{location: location}
~H"""
-
- <.location_header tooltip="The devices location is announced by the device after it connects." />
-
-
- An error occurred during location resolution : {@location["error_code"]}
+
+
+
Location
+
The devices location is announced by the device after it connects.
-
- {@location["error_description"]}
+
+
+
+
+
An error occurred during location resolution : {@location["error_code"]}
+
{@location["error_description"]}
+
"""
end
- ###
- # TODO: add support for marker and increased zoom when source is gps
- ###
-
# yay, we have a location and map key, lets display a map
def render(%{location: location} = assigns) do
assigns = %{
lat: location["latitude"],
lng: location["longitude"],
source: location["source"],
- zoom: 10,
- size: "463x250",
- mapbox_access_token: assigns.mapbox_access_token
+ zoom: if(String.downcase(location["source"]) == "gps", do: 15, else: 13),
+ mapbox_access_token: assigns.mapbox_access_token,
+ target: assigns[:target]
}
- ~H"""
-
- <.location_header tooltip={"The devices location was determined via #{@source}"} />
+ source_information =
+ case location["source"] do
+ "manual" -> "The location was manually configured."
+ _ -> "The location was determined via #{location["source"]} resolution."
+ end
-
-
- """
- end
+ assigns = Map.put(assigns, :source_information, source_information)
- attr(:tooltip, :string)
-
- defp location_header(assigns) do
~H"""
-
- Device location
-
- {@tooltip}
+
+
+
Location
+
+ {@source_information}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
"""
end
diff --git a/lib/nerves_hub_web/components/device_page/activity.ex b/lib/nerves_hub_web/components/device_page/activity_tab.ex
similarity index 88%
rename from lib/nerves_hub_web/components/device_page/activity.ex
rename to lib/nerves_hub_web/components/device_page/activity_tab.ex
index 7a7d1f3cd..5cbd8a4ee 100644
--- a/lib/nerves_hub_web/components/device_page/activity.ex
+++ b/lib/nerves_hub_web/components/device_page/activity_tab.ex
@@ -1,15 +1,18 @@
-defmodule NervesHubWeb.Components.DevicePage.Activity do
- use NervesHubWeb, :live_component
+defmodule NervesHubWeb.Components.DevicePage.ActivityTab do
+ use NervesHubWeb, tab_component: :activity
alias NervesHub.AuditLogs
alias NervesHubWeb.Components.Pager
- def update(assigns, socket) do
+ def tab_params(_params, _uri, socket) do
socket
- |> assign(assigns)
|> logs_and_pager_assigns()
- |> ok()
+ |> cont()
+ end
+
+ def cleanup() do
+ [:activity, :audit_pager]
end
defp logs_and_pager_assigns(socket, page_number \\ 1, page_size \\ 25) do
@@ -82,12 +85,12 @@ defmodule NervesHubWeb.Components.DevicePage.Activity do
-
+
"""
end
- def handle_event("set-paginate-opts", %{"page-size" => page_size}, socket) do
+ def hooked_event("set-paginate-opts", %{"page-size" => page_size}, socket) do
params = %{"page_size" => page_size, "page_number" => 1}
url =
@@ -96,10 +99,10 @@ defmodule NervesHubWeb.Components.DevicePage.Activity do
socket
|> logs_and_pager_assigns(1, String.to_integer(page_size))
|> push_patch(to: url)
- |> noreply()
+ |> halt()
end
- def handle_event("paginate", %{"page" => page_num}, socket) do
+ def hooked_event("paginate", %{"page" => page_num}, socket) do
params = %{"page_size" => socket.assigns.audit_pager.page_size, "page_number" => page_num}
url =
@@ -111,6 +114,12 @@ defmodule NervesHubWeb.Components.DevicePage.Activity do
socket.assigns.audit_pager.page_size
)
|> push_patch(to: url)
- |> noreply()
+ |> halt()
end
+
+ def hooked_event(_name, _params, socket), do: {:cont, socket}
+
+ def hooked_info(_name, socket), do: {:cont, socket}
+
+ def hooked_async(_name, _async_fun_result, socket), do: {:cont, socket}
end
diff --git a/lib/nerves_hub_web/components/device_page/console.ex b/lib/nerves_hub_web/components/device_page/console.ex
deleted file mode 100644
index 9f3bc32f5..000000000
--- a/lib/nerves_hub_web/components/device_page/console.ex
+++ /dev/null
@@ -1,112 +0,0 @@
-defmodule NervesHubWeb.Components.DevicePage.Console do
- use NervesHubWeb, :live_component
-
- alias NervesHub.Tracker
- alias Phoenix.LiveView.JS
-
- def update(%{file_upload: payload}, socket) do
- if socket.assigns.user.id == payload.uploaded_by do
- case payload.status do
- "started" ->
- send_toast(socket, :info, "Upload started.")
-
- "finished" ->
- send_toast(socket, :info, "Upload finished.")
-
- _ ->
- true
- end
- end
-
- ok(socket)
- end
-
- def update(assigns, socket) do
- socket
- |> assign(assigns)
- |> assign(:user_token, Phoenix.Token.sign(socket, "user salt", assigns.user.id))
- |> assign(:console_active?, Tracker.console_active?(assigns.device))
- |> ok()
- end
-
- def toggle_fullscreen(js \\ %JS{}) do
- js
- # Dropzone
- # disable relative
- |> JS.toggle_class("relative", to: "#dropzone")
- |> JS.toggle_class("fixed", to: "#dropzone")
- |> JS.toggle_class("top-0", to: "#dropzone")
- |> JS.toggle_class("left-0", to: "#dropzone")
- |> JS.toggle_class("right-0", to: "#dropzone")
- |> JS.toggle_class("bottom-0", to: "#dropzone")
- # disable p-12
- |> JS.toggle_class("p-12", to: "#dropzone")
- |> JS.toggle_class("p-6", to: "#dropzone")
- |> JS.toggle_class("pt-14", to: "#dropzone")
- |> JS.toggle_class("pb-4", to: "#dropzone")
- |> JS.toggle_class("box-border", to: "#dropzone")
-
- # Immersive device information
- |> JS.toggle(to: "#immersive-device")
-
- # Console
- |> JS.toggle_class("box-border", to: "#console")
- # disable w-full
- |> JS.toggle_class("w-full", to: "#console")
- # disable h-full
- |> JS.toggle_class("h-full", to: "#console")
-
- # Fullscreen/Close button
- # disable right-16
- |> JS.toggle_class("right-16", to: "#fullscreen")
- |> JS.toggle_class("right-4", to: "#fullscreen")
- # disable top-8
- |> JS.toggle_class("top-8", to: "#fullscreen")
- |> JS.toggle_class("top-4", to: "#fullscreen")
- |> JS.toggle_class("hidden", to: "#fullscreen svg")
- end
-
- def render(assigns) do
- ~H"""
-
-
-
-
-
-
-
- <%= if Map.get(@device_connection || %{}, :status) == :connected do %>
-
- <% else %>
-
- <% end %>
-
- {@device.identifier}
-
-
-
-
-
-
- The device console isn't currently available.
-
-
- You don't have the required permissions to access a Device console.
-
-
-
-
- """
- end
-end
diff --git a/lib/nerves_hub_web/components/device_page/console_tab.ex b/lib/nerves_hub_web/components/device_page/console_tab.ex
new file mode 100644
index 000000000..518093626
--- /dev/null
+++ b/lib/nerves_hub_web/components/device_page/console_tab.ex
@@ -0,0 +1,157 @@
+defmodule NervesHubWeb.Components.DevicePage.ConsoleTab do
+ use NervesHubWeb, tab_component: :console
+
+ alias NervesHub.Tracker
+
+ alias Phoenix.LiveView.AsyncResult
+ alias Phoenix.LiveView.JS
+
+ def tab_params(_params, _uri, socket) do
+ device = socket.assigns.device
+
+ socket
+ |> assign_async(
+ :console_active?,
+ fn ->
+ {:ok, %{console_active?: Tracker.console_active?(device)}}
+ end,
+ reset: true
+ )
+ |> cont()
+ end
+
+ def cleanup() do
+ [:console_active?]
+ end
+
+ def hooked_info(%Broadcast{event: "console_joined"}, socket) do
+ socket
+ |> assign(:console_active?, AsyncResult.ok(true))
+ |> halt()
+ end
+
+ def hooked_info(%Broadcast{event: "file-data/start", payload: payload}, socket) do
+ if socket.assigns.user.id == payload.uploaded_by do
+ send_toast(socket, :info, "Upload started.")
+ else
+ socket
+ end
+ |> halt()
+ end
+
+ def hooked_info(%Broadcast{event: "file-data/stop", payload: payload}, socket) do
+ if socket.assigns.user.id == payload.uploaded_by do
+ send_toast(socket, :info, "Upload finished.")
+ else
+ socket
+ end
+ |> halt()
+ end
+
+ def hooked_info(_event, socket), do: {:cont, socket}
+
+ def hooked_event(_event, _params, socket), do: {:cont, socket}
+
+ def hooked_async(_name, _async_fun_result, socket), do: {:cont, socket}
+
+ def toggle_fullscreen(js \\ %JS{}) do
+ js
+ # Dropzone
+ # disable relative
+ |> JS.toggle_class("relative", to: "#dropzone")
+ |> JS.toggle_class("fixed", to: "#dropzone")
+ |> JS.toggle_class("top-0", to: "#dropzone")
+ |> JS.toggle_class("left-0", to: "#dropzone")
+ |> JS.toggle_class("right-0", to: "#dropzone")
+ |> JS.toggle_class("bottom-0", to: "#dropzone")
+ # disable p-12
+ |> JS.toggle_class("p-12", to: "#dropzone")
+ |> JS.toggle_class("p-6", to: "#dropzone")
+ |> JS.toggle_class("pt-14", to: "#dropzone")
+ |> JS.toggle_class("pb-4", to: "#dropzone")
+ |> JS.toggle_class("box-border", to: "#dropzone")
+
+ # Immersive device information
+ |> JS.toggle(to: "#immersive-device")
+
+ # Console
+ |> JS.toggle_class("box-border", to: "#console")
+ # disable w-full
+ |> JS.toggle_class("w-full", to: "#console")
+ # disable h-full
+ |> JS.toggle_class("h-full", to: "#console")
+
+ # Fullscreen/Close button
+ # disable right-16
+ |> JS.toggle_class("right-16", to: "#fullscreen")
+ |> JS.toggle_class("right-4", to: "#fullscreen")
+ # disable top-8
+ |> JS.toggle_class("top-8", to: "#fullscreen")
+ |> JS.toggle_class("top-4", to: "#fullscreen")
+ |> JS.toggle_class("hidden", to: "#fullscreen svg")
+ end
+
+ def render(assigns) do
+ token = Phoenix.Token.sign(NervesHubWeb.Endpoint, "user salt", assigns.user.id)
+
+ assigns = Map.put(assigns, :user_token, token)
+
+ ~H"""
+
+ There was an error checking if the device was online.
+
+
+
+
+
+
+
+
+ <%= if Map.get(@device_connection || %{}, :status) == :connected do %>
+
+ <% else %>
+
+ <% end %>
+
+ {@device.identifier}
+
+
+
+
+
+
+ The device console isn't currently available.
+
+
+ You don't have the required permissions to access a Device console.
+
+
+
+
+
+ """
+ end
+end
diff --git a/lib/nerves_hub_web/components/device_page/details.ex b/lib/nerves_hub_web/components/device_page/details_tab.ex
similarity index 86%
rename from lib/nerves_hub_web/components/device_page/details.ex
rename to lib/nerves_hub_web/components/device_page/details_tab.ex
index 547340f86..d7cc7b1f9 100644
--- a/lib/nerves_hub_web/components/device_page/details.ex
+++ b/lib/nerves_hub_web/components/device_page/details_tab.ex
@@ -1,5 +1,5 @@
-defmodule NervesHubWeb.Components.DevicePage.Details do
- use NervesHubWeb, :live_component
+defmodule NervesHubWeb.Components.DevicePage.DetailsTab do
+ use NervesHubWeb, tab_component: :details
require Logger
@@ -14,50 +14,32 @@ defmodule NervesHubWeb.Components.DevicePage.Details do
alias NervesHub.Scripts
alias NervesHubWeb.Components.HealthStatus
- alias NervesHubWeb.Components.NewUI.DeviceLocation
-
- def update(%{latest_metrics: latest_metrics}, socket) do
- socket
- |> assign(:latest_metrics, latest_metrics)
- |> assign_metadata()
- |> ok()
- end
-
- def update(%{update_auto_refresh_health: auto_refresh_health}, socket) do
- socket
- |> assign(:auto_refresh_health, auto_refresh_health)
- |> ok()
- end
-
- def update(%{firmwares: firmware}, socket) do
- socket
- |> assign(:firmwares, firmware)
- |> send_toast(:info, "New firmware available for selection")
- |> ok()
- end
-
- def update(assigns, socket) do
- device = Devices.get_complete_device(assigns.device_id)
-
+ alias NervesHubWeb.Components.DeviceLocation
+
+ @keys_to_cleanup [
+ :support_scripts,
+ :firmwares,
+ :update_information,
+ :alarms,
+ :extension_overrides,
+ :deployment_groups
+ ]
+
+ def tab_params(_params, _uri, %{assigns: %{device: device}} = socket) do
socket
- |> assign(:device, device)
- |> assign(:product, device.product)
- |> assign(:org, device.org)
- |> assign(:org_user, assigns.org_user)
- |> assign(:user, assigns.user)
- |> assign(:device_connection, device.latest_connection)
|> assign_support_scripts()
|> assign(:firmwares, Firmwares.get_firmware_for_device(device))
|> assign(:update_information, Devices.resolve_update(device))
|> assign(:latest_metrics, Metrics.get_latest_metric_set(device.id))
|> assign(:alarms, Alarms.get_current_alarms_for_device(device))
|> assign(:extension_overrides, extension_overrides(device, device.product))
- |> assign(:auto_refresh_health, true)
|> assign_metadata()
|> assign_deployment_groups()
- |> ok()
+ |> cont()
end
+ def cleanup(), do: @keys_to_cleanup
+
defp assign_metadata(%{assigns: %{device: device}} = socket) do
health = Devices.get_latest_health(device.id)
@@ -76,16 +58,19 @@ defmodule NervesHubWeb.Components.DevicePage.Details do
assign(socket, :support_scripts, scripts)
end
- defp assign_deployment_groups(%{assigns: %{device: %{status: :provisioned} = device}} = socket),
- do: assign(socket, deployment_groups: ManagedDeployments.eligible_deployment_groups(device))
+ defp assign_deployment_groups(%{assigns: %{device: %{status: :provisioned} = device}} = socket) do
+ assign(socket, deployment_groups: ManagedDeployments.eligible_deployment_groups(device))
+ end
- defp assign_deployment_groups(%{assigns: %{product: product}} = socket),
- do:
- assign(socket,
- deployment_groups: ManagedDeployments.get_deployment_groups_by_product(product)
- )
+ defp assign_deployment_groups(%{assigns: %{product: product}} = socket) do
+ assign(socket,
+ deployment_groups: ManagedDeployments.get_deployment_groups_by_product(product)
+ )
+ end
def render(assigns) do
+ assigns = Map.put(assigns, :auto_refresh_health, !!assigns.health_check_timer)
+
~H"""
@@ -196,7 +181,7 @@ defmodule NervesHubWeb.Components.DevicePage.Details do
Health
-
+
No device health information has been received.
@@ -307,7 +292,6 @@ defmodule NervesHubWeb.Components.DevicePage.Details do
data-confirm="Are you sure you want to remove the device from the deployment?"
aria-label="Remove device from the assigned deployment group"
type="button"
- phx-target={@myself}
phx-click="remove-from-deployment-group"
>