From 11a31ae088bef009e05d7197d4c6cd313f0e2978 Mon Sep 17 00:00:00 2001 From: bmanifold Date: Fri, 4 Aug 2023 15:17:11 -0400 Subject: [PATCH] Refactor Actor and Device Liveviews (#1824) Why: * The previous Actor and Device Liveviews had used static views and data as a starting point for fleshing out the web UI. This commit builds on that and replaces (most) of the static data with data from the database, as well as updating the static Liveview templates to use components where possible. --- elixir/apps/domain/lib/domain/actors.ex | 25 +- elixir/apps/domain/lib/domain/devices.ex | 21 +- elixir/apps/domain/priv/repo/seeds.exs | 25 ++ .../apps/domain/test/domain/actors_test.exs | 27 ++ .../lib/web/components/layouts/app.html.heex | 18 +- .../web/components/navigation_components.ex | 4 +- .../lib/web/components/table_components.ex | 24 +- elixir/apps/web/lib/web/live/actors/edit.ex | 108 ++++++ elixir/apps/web/lib/web/live/actors/index.ex | 128 +++++++ .../web/lib/web/live/{users => actors}/new.ex | 2 +- elixir/apps/web/lib/web/live/actors/show.ex | 116 ++++++ elixir/apps/web/lib/web/live/devices/index.ex | 339 +++++------------- elixir/apps/web/lib/web/live/devices/show.ex | 180 +++------- elixir/apps/web/lib/web/live/users/edit.ex | 128 ------- elixir/apps/web/lib/web/live/users/index.ex | 278 -------------- elixir/apps/web/lib/web/live/users/show.ex | 126 ------- elixir/apps/web/lib/web/router.ex | 2 +- 17 files changed, 611 insertions(+), 940 deletions(-) create mode 100644 elixir/apps/web/lib/web/live/actors/edit.ex create mode 100644 elixir/apps/web/lib/web/live/actors/index.ex rename elixir/apps/web/lib/web/live/{users => actors}/new.ex (99%) create mode 100644 elixir/apps/web/lib/web/live/actors/show.ex delete mode 100644 elixir/apps/web/lib/web/live/users/edit.ex delete mode 100644 elixir/apps/web/lib/web/live/users/index.ex delete mode 100644 elixir/apps/web/lib/web/live/users/show.ex diff --git a/elixir/apps/domain/lib/domain/actors.ex b/elixir/apps/domain/lib/domain/actors.ex index 37d28e45d..4e2f2e37f 100644 --- a/elixir/apps/domain/lib/domain/actors.ex +++ b/elixir/apps/domain/lib/domain/actors.ex @@ -129,12 +129,18 @@ defmodule Domain.Actors do end end - def fetch_actor_by_id(id, %Auth.Subject{} = subject) do + def fetch_actor_by_id(id, %Auth.Subject{} = subject, opts \\ []) do + {preload, _opts} = Keyword.pop(opts, :preload, []) + with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()), true <- Validator.valid_uuid?(id) do Actor.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() + |> case do + {:ok, actor} -> {:ok, Repo.preload(actor, preload)} + {:error, reason} -> {:error, reason} + end else false -> {:error, :not_found} other -> other @@ -156,14 +162,17 @@ defmodule Domain.Actors do end def list_actors(%Auth.Subject{} = subject, opts \\ []) do - with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do - {hydrate, _opts} = Keyword.pop(opts, :hydrate, []) + {preload, _opts} = Keyword.pop(opts, :preload, []) + {hydrate, _opts} = Keyword.pop(opts, :hydrate, []) - Actor.Query.all() - |> Authorizer.for_subject(subject) - # TODO: add filters - |> hydrate_fields(hydrate) - |> Repo.list() + with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do + {:ok, actors} = + Actor.Query.all() + |> Authorizer.for_subject(subject) + |> hydrate_fields(hydrate) + |> Repo.list() + + {:ok, Repo.preload(actors, preload)} end end diff --git a/elixir/apps/domain/lib/domain/devices.ex b/elixir/apps/domain/lib/domain/devices.ex index 2dd121ee0..1cba291a1 100644 --- a/elixir/apps/domain/lib/domain/devices.ex +++ b/elixir/apps/domain/lib/domain/devices.ex @@ -26,7 +26,9 @@ defmodule Domain.Devices do |> Repo.aggregate(:count) end - def fetch_device_by_id(id, %Auth.Subject{} = subject) do + def fetch_device_by_id(id, %Auth.Subject{} = subject, opts \\ []) do + {preload, _opts} = Keyword.pop(opts, :preload, []) + required_permissions = {:one_of, [ @@ -39,6 +41,10 @@ defmodule Domain.Devices do Device.Query.by_id(id) |> Authorizer.for_subject(subject) |> Repo.fetch() + |> case do + {:ok, device} -> {:ok, Repo.preload(device, preload)} + {:error, reason} -> {:error, reason} + end else false -> {:error, :not_found} other -> other @@ -53,7 +59,9 @@ defmodule Domain.Devices do |> Repo.preload(preload) end - def list_devices(%Auth.Subject{} = subject) do + def list_devices(%Auth.Subject{} = subject, opts \\ []) do + {preload, _opts} = Keyword.pop(opts, :preload, []) + required_permissions = {:one_of, [ @@ -62,9 +70,12 @@ defmodule Domain.Devices do ]} with :ok <- Auth.ensure_has_permissions(subject, required_permissions) do - Device.Query.all() - |> Authorizer.for_subject(subject) - |> Repo.list() + {:ok, devices} = + Device.Query.all() + |> Authorizer.for_subject(subject) + |> Repo.list() + + {:ok, Repo.preload(devices, preload)} end end diff --git a/elixir/apps/domain/priv/repo/seeds.exs b/elixir/apps/domain/priv/repo/seeds.exs index 8f3e2422c..076240589 100644 --- a/elixir/apps/domain/priv/repo/seeds.exs +++ b/elixir/apps/domain/priv/repo/seeds.exs @@ -146,6 +146,31 @@ end IO.puts("") +user_iphone = + Domain.Devices.upsert_device( + %{ + name: "FZ User iPhone", + external_id: Ecto.UUID.generate(), + public_key: :crypto.strong_rand_bytes(32) |> Base.encode64(), + last_seen_user_agent: "iOS/12.7 (iPhone) connlib/0.7.412" + }, + unprivileged_subject + ) + +admin_iphone = + Domain.Devices.upsert_device( + %{ + name: "FZ Admin iPhone", + external_id: Ecto.UUID.generate(), + public_key: :crypto.strong_rand_bytes(32) |> Base.encode64(), + last_seen_user_agent: "iOS/12.7 (iPhone) connlib/0.7.412" + }, + admin_subject + ) + +IO.puts("Devices created") +IO.puts("") + relay_group = account |> Relays.Group.Changeset.create_changeset( diff --git a/elixir/apps/domain/test/domain/actors_test.exs b/elixir/apps/domain/test/domain/actors_test.exs index 086c26cb2..79c667667 100644 --- a/elixir/apps/domain/test/domain/actors_test.exs +++ b/elixir/apps/domain/test/domain/actors_test.exs @@ -624,6 +624,17 @@ defmodule Domain.ActorsTest do {:unauthorized, [missing_permissions: [Actors.Authorizer.manage_actors_permission()]]}} end + + test "associations are preloaded when opts given" do + account = AccountsFixtures.create_account() + actor = ActorsFixtures.create_actor(type: :account_admin_user, account: account) + identity = AuthFixtures.create_identity(account: account, actor: actor) + subject = AuthFixtures.create_subject(identity) + + {:ok, actor} = fetch_actor_by_id(actor.id, subject, preload: :identities) + + assert Ecto.assoc_loaded?(actor.identities) == true + end end describe "fetch_actor_by_id/1" do @@ -704,6 +715,22 @@ defmodule Domain.ActorsTest do {:unauthorized, [missing_permissions: [Actors.Authorizer.manage_actors_permission()]]}} end + + test "associations are preloaded when opts given" do + account = AccountsFixtures.create_account() + + actor1 = ActorsFixtures.create_actor(type: :account_admin_user, account: account) + identity1 = AuthFixtures.create_identity(account: account, actor: actor1) + subject = AuthFixtures.create_subject(identity1) + + actor2 = ActorsFixtures.create_actor(type: :account_user, account: account) + AuthFixtures.create_identity(account: account, actor: actor2) + + {:ok, actors} = list_actors(subject, preload: :identities) + assert length(actors) == 2 + + assert Enum.all?(actors, fn a -> Ecto.assoc_loaded?(a.identities) end) == true + end end describe "create_actor/4" do diff --git a/elixir/apps/web/lib/web/components/layouts/app.html.heex b/elixir/apps/web/lib/web/components/layouts/app.html.heex index 1207b83bc..f42e4c899 100644 --- a/elixir/apps/web/lib/web/components/layouts/app.html.heex +++ b/elixir/apps/web/lib/web/components/layouts/app.html.heex @@ -101,13 +101,15 @@ Dashboard - <.sidebar_item_group id="organization"> - <:name>Organization - - <:item navigate={~p"/#{@account}/actors"}>Users - <:item navigate={~p"/#{@account}/groups"}>Groups - <:item navigate={~p"/#{@account}/devices"}>Devices - + <.sidebar_item navigate={~p"/#{@account}/actors"} icon="hero-user-circle-solid"> + Actors + + <.sidebar_item navigate={~p"/#{@account}/groups"} icon="hero-user-group-solid"> + Groups + + <.sidebar_item navigate={~p"/#{@account}/devices"} icon="hero-device-phone-mobile-solid"> + Devices + <.sidebar_item navigate={~p"/#{@account}/gateways"} icon="hero-arrow-left-on-rectangle-solid"> Gateways @@ -121,7 +123,7 @@ Policies - <.sidebar_item_group id="settings"> + <.sidebar_item_group id="settings" icon="hero-cog-solid"> <:name>Settings <:item navigate={~p"/#{@account}/settings/account"}>Account diff --git a/elixir/apps/web/lib/web/components/navigation_components.ex b/elixir/apps/web/lib/web/components/navigation_components.ex index bd3de26ea..094bfb1ae 100644 --- a/elixir/apps/web/lib/web/components/navigation_components.ex +++ b/elixir/apps/web/lib/web/components/navigation_components.ex @@ -55,7 +55,7 @@ defmodule Web.NavigationComponents do end attr :id, :string, required: true, doc: "ID of the nav group container" - # attr :icon, :string, required: true + attr :icon, :string, required: true # attr :navigate, :string, required: true slot :name, required: true @@ -77,7 +77,7 @@ defmodule Web.NavigationComponents do aria-controls={"dropdown-#{@id}"} data-collapse-toggle={"dropdown-#{@id}"} > - <.icon name="hero-user-group-solid" class={~w[ + <.icon name={@icon} class={~w[ w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 diff --git a/elixir/apps/web/lib/web/components/table_components.ex b/elixir/apps/web/lib/web/components/table_components.ex index d88f5dcf6..1ccfd7048 100644 --- a/elixir/apps/web/lib/web/components/table_components.ex +++ b/elixir/apps/web/lib/web/components/table_components.ex @@ -223,9 +223,14 @@ defmodule Web.TableComponents do """ + attr :class, :string, default: nil + attr :rest, :global + + slot :inner_block + def vertical_table(assigns) do ~H""" - +
<%= render_slot(@inner_block) %> @@ -250,19 +255,26 @@ defmodule Web.TableComponents do """ + attr :label_class, :string, default: nil + attr :value_class, :string, default: nil + slot :label, doc: "the slot for rendering the label of a row" slot :value, doc: "the slot for rendering the value of a row" def vertical_table_row(assigns) do ~H""" - - diff --git a/elixir/apps/web/lib/web/live/actors/edit.ex b/elixir/apps/web/lib/web/live/actors/edit.ex new file mode 100644 index 000000000..a3c45346d --- /dev/null +++ b/elixir/apps/web/lib/web/live/actors/edit.ex @@ -0,0 +1,108 @@ +defmodule Web.Actors.Edit do + use Web, :live_view + + alias Domain.Actors + + def mount(%{"id" => id} = _params, _session, socket) do + {:ok, actor} = Actors.fetch_actor_by_id(id, socket.assigns.subject) + + {:ok, assign(socket, actor: actor)} + end + + def render(assigns) do + ~H""" + <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> + <.breadcrumb path={~p"/#{@account}/actors"}>Actors + <.breadcrumb path={~p"/#{@account}/actors/#{@actor.id}"}> + <%= @actor.name %> + + <.breadcrumb path={~p"/#{@account}/actors/#{@actor.id}/edit"}> + Edit + + + <.header> + <:title> + Editing User: <%= @actor.name %> + + + +
+
+

Edit User Details

+
+
+
+ <.label for="first-name"> + Name + + <.input type="text" name="name" id="name" value={@actor.name} required="" /> +
+
+ <.label for="email"> + Email + + <.input + aria-describedby="email-explanation" + type="email" + name="email" + id="email" + value="TODO: Email here" + /> +

+ We'll send a confirmation email to both the current email address and the updated one to confirm the change. +

+
+
+ <.label for="confirm-email"> + Confirm email + + <.input type="email" name="confirm-email" id="confirm-email" value="TODO" /> +
+
+ <.label for="user-role"> + Role + + <.input + type="select" + id="user-role" + name="user-role" + options={[ + "End User": :account_user, + Admin: :account_admin_user, + "Service Account": :service_account + ]} + value={@actor.type} + /> +

+ Select Admin to make this user an administrator of your organization. +

+
+
+ <.label for="user-groups"> + Groups + + <.input + type="select" + multiple={true} + name="user-groups" + id="user-groups" + options={["TODO: Devops", "TODO: Engineering", "TODO: Accounting"]} + value="" + /> + +

+ Select one or more groups to allow this user access to resources. +

+
+
+
+ <.button type="submit"> + Save + +
+ +
+
+ """ + end +end diff --git a/elixir/apps/web/lib/web/live/actors/index.ex b/elixir/apps/web/lib/web/live/actors/index.ex new file mode 100644 index 000000000..596b5041b --- /dev/null +++ b/elixir/apps/web/lib/web/live/actors/index.ex @@ -0,0 +1,128 @@ +defmodule Web.Actors.Index do + use Web, :live_view + + alias Domain.Actors + + def mount(_params, _session, socket) do + {_, actors} = Actors.list_actors(socket.assigns.subject, preload: [identities: :provider]) + + {:ok, assign(socket, actors: actors)} + end + + defp actor_icon(type) do + case type do + :account_user -> "hero-user-circle-solid" + :account_admin_user -> "hero-user-circle-solid" + :service_account -> "hero-server-solid" + end + end + + def render(assigns) do + ~H""" + <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> + <.breadcrumb path={~p"/#{@account}/actors"}>Actors + + <.header> + <:title> + All Actors + + <:actions> + <.add_button navigate={~p"/#{@account}/actors/new"}> + Add a new user + + + + +
+ <.resource_filter /> + <.table id="actors" rows={@actors} row_id={&"user-#{&1.id}"}> + <:col :let={actor} label="TYPE" sortable="false"> + <.icon name={actor_icon(actor.type)} class="w-5 h-5" /> + + <:col :let={actor} label="NAME" sortable="false"> + <.link + navigate={~p"/#{@account}/actors/#{actor.id}"} + class="font-medium text-blue-600 dark:text-blue-500 hover:underline" + > + <%= actor.name %> + + + <:col :let={actor} label="IDENTIFIERS" sortable="false"> + <%= for identity <- actor.identities do %> + <%= "#{identity.provider.name}: #{identity.provider_identifier}" %> +
+ <% end %> + + <:col :let={_actor} label="GROUPS" sortable="false"> + + <%= "TODO Admin, Engineering, 3 more..." %> + + <:col :let={_actor} label="LAST ACTIVE" sortable="false"> + + <%= "TODO Today at 2:30pm" %> + + <:action> + <.link + navigate={~p"/#{@account}/actors/#{@subject.actor.id}"} + class="block py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" + > + Show + + + <:action> + <.link + navigate={~p"/#{@account}/actors/#{@subject.actor.id}/edit"} + class="block py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" + > + Edit + + + <:action> + + Delete + + + + <.paginator page={3} total_pages={100} collection_base_path={~p"/#{@account}/actors"} /> +
+ """ + end + + defp resource_filter(assigns) do + ~H""" +
+
+
+ +
+
+ <.icon name="hero-magnifying-glass" class="w-5 h-5 text-gray-500 dark:text-gray-400" /> +
+ +
+ +
+ <.button_group> + <:first> + All + + <:middle> + Users + + <:last> + Service Accounts + + +
+ """ + end +end diff --git a/elixir/apps/web/lib/web/live/users/new.ex b/elixir/apps/web/lib/web/live/actors/new.ex similarity index 99% rename from elixir/apps/web/lib/web/live/users/new.ex rename to elixir/apps/web/lib/web/live/actors/new.ex index 875540fea..0b0d58de2 100644 --- a/elixir/apps/web/lib/web/live/users/new.ex +++ b/elixir/apps/web/lib/web/live/actors/new.ex @@ -1,4 +1,4 @@ -defmodule Web.Users.New do +defmodule Web.Actors.New do use Web, :live_view def render(assigns) do diff --git a/elixir/apps/web/lib/web/live/actors/show.ex b/elixir/apps/web/lib/web/live/actors/show.ex new file mode 100644 index 000000000..bfd1394f6 --- /dev/null +++ b/elixir/apps/web/lib/web/live/actors/show.ex @@ -0,0 +1,116 @@ +defmodule Web.Actors.Show do + use Web, :live_view + + alias Domain.Actors + + def mount(%{"id" => id} = _params, _session, socket) do + {:ok, actor} = + Actors.fetch_actor_by_id(id, socket.assigns.subject, preload: [identities: [:provider]]) + + {:ok, assign(socket, actor: actor)} + end + + defp account_type_to_string(type) do + case type do + :account_admin_user -> "Admin" + :account_user -> "User" + :service_account -> "Service Account" + end + end + + def render(assigns) do + ~H""" + <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> + <.breadcrumb path={~p"/#{@account}/actors"}>Actors + <.breadcrumb path={~p"/#{@account}/actors/#{@actor.id}"}> + <%= @actor.name %> + + + <.header> + <:title> + Viewing User: <%= @actor.name %> + + <:actions> + <.edit_button navigate={~p"/#{@account}/actors/#{@actor.id}/edit"}> + Edit user + + + + +
+
User Info
+ <.vertical_table> + <.vertical_table_row label_class="w-1/5"> + <:label>Name + <:value><%= @actor.name %> + + <.vertical_table_row> + <:label>Source + <:value>TODO: Manually created by Jamil Bou Kheir on May 3rd, 2023. + + <.vertical_table_row> + <:label>Role + <:value> + <%= account_type_to_string(@actor.type) %> + + + <.vertical_table_row> + <:label>Groups + <:value>TODO: Groups Here + + <.vertical_table_row> + <:label>Last Active + <:value>TODO: Last Active Here + + +
+
+
+ Authentication Identities +
+ <.identity :for={identity <- @actor.identities} class="mb-4"> + <:provider><%= identity.provider.name %> + <:identity><%= identity.provider_identifier %> + <:last_auth><%= identity.last_seen_at %> + +
+ <.header> + <:title> + Danger zone + + <:actions> + <.delete_button> + Delete user + + + + """ + end + + attr(:rest, :global) + + slot(:provider) + slot(:identity) + slot(:last_auth) + + def identity(assigns) do + ~H""" +
+ <.vertical_table class="table-fixed"> + <.vertical_table_row label_class="w-1/5"> + <:label>Provider + <:value><%= render_slot(@provider) %> + + <.vertical_table_row> + <:label>Identity + <:value><%= render_slot(@identity) %> + + <.vertical_table_row> + <:label>Last Authentication + <:value><%= render_slot(@last_auth) %> + + +
+ """ + end +end diff --git a/elixir/apps/web/lib/web/live/devices/index.ex b/elixir/apps/web/lib/web/live/devices/index.ex index 66c43ae86..9f2d8f8d0 100644 --- a/elixir/apps/web/lib/web/live/devices/index.ex +++ b/elixir/apps/web/lib/web/live/devices/index.ex @@ -1,6 +1,14 @@ defmodule Web.Devices.Index do use Web, :live_view + alias Domain.Devices + + def mount(_params, _session, socket) do + {_, devices} = Devices.list_devices(socket.assigns.subject, preload: :actor) + + {:ok, assign(socket, devices: devices)} + end + def render(assigns) do ~H""" <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> @@ -13,264 +21,83 @@ defmodule Web.Devices.Index do
-
-
-
- -
-
- <.icon name="hero-magnifying-glass" class="w-5 h-5 text-gray-500 dark:text-gray-400" /> -
- -
- -
- <.button_group> - <:first> - All - - <:middle> - Online - - <:last> - Archived - - -
-
-
+ <%= render_slot(@label) %> + <%= render_slot(@value) %>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - Actions -
- <.link - navigate={~p"/#{@account}/devices/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - v1.01 Linux - - - <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - John Doe - - - - Online - - - - -
- <.link - navigate={~p"/#{@account}/devices/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - v1.01 iOS - - - <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - Steve Johnson - - - - Last seen 2 hours ago - - - - -
- <.link - navigate={~p"/#{@account}/devices/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - v1.01 macOS - - - <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - Steinberg, Gabriel - - - - Archived 6 months ago - - - - -
- + <.resource_filter /> + <.table id="devices" rows={@devices} row_id={&"device-#{&1.id}"}> + <:col :let={device} label="CLIENT" sortable="true"> + <.link + navigate={~p"/#{@account}/devices/#{device.id}"} + class="font-medium text-blue-600 dark:text-blue-500 hover:underline" + > + <%= device.name %> + + + <:col :let={device} label="USER" sortable="true"> + <.link + navigate={~p"/#{@account}/actors/#{device.actor.id}"} + class="font-medium text-blue-600 dark:text-blue-500 hover:underline" + > + <%= device.actor.name %> + + + <:col :let={_device} label="STATUS" sortable="true"> + <.badge type="success"> + TODO: Online + + + <:action :let={device}> + <.link + navigate={~p"/#{@account}/devices/#{device.id}"} + class="block py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white" + > + Show + + + <:action> + + TODO: Archive + + + <.paginator page={3} total_pages={100} collection_base_path={~p"/#{@account}/devices"} /> """ end + + defp resource_filter(assigns) do + ~H""" +
+
+
+ +
+
+ <.icon name="hero-magnifying-glass" class="w-5 h-5 text-gray-500 dark:text-gray-400" /> +
+ +
+
+
+ <.button_group> + <:first> + All + + <:middle> + Online + + <:last> + Archived + + +
+ """ + end end diff --git a/elixir/apps/web/lib/web/live/devices/show.ex b/elixir/apps/web/lib/web/live/devices/show.ex index 4e8d9d263..14281e649 100644 --- a/elixir/apps/web/lib/web/live/devices/show.ex +++ b/elixir/apps/web/lib/web/live/devices/show.ex @@ -1,141 +1,79 @@ defmodule Web.Devices.Show do use Web, :live_view + alias Domain.Devices + + def mount(%{"id" => id} = _params, _session, socket) do + {:ok, device} = Devices.fetch_device_by_id(id, socket.assigns.subject, preload: :actor) + + {:ok, assign(socket, device: device)} + end + def render(assigns) do ~H""" <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> <.breadcrumb path={~p"/#{@account}/devices"}>Devices - <.breadcrumb path={~p"/#{@account}/devices/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"}> - Jamil's Macbook Pro + <.breadcrumb path={~p"/#{@account}/devices/#{@device.id}"}> + <%= @device.name %> <.header> <:title> - Device details + Device Details
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ <.vertical_table_row> + <:label>Identifier + <:value><%= @device.id %> + + <.vertical_table_row> + <:label>Owner + <:value> + <.link + navigate={~p"/#{@account}/actors/#{@device.actor.id}"} + class="font-medium text-blue-600 dark:text-blue-500 hover:underline" > - Identifier - - BF0F8D31FA89 -
- User - - <.link - navigate={~p"/#{@account}/actors/55DDA8CB-69A7-48FC-9048-639021C205A2"} - class="text-blue-600 hover:underline" - > - Andrew Dryga - -
- First seen - - 3 days ago in Bangalore, India -
- Last seen - - 1 hour ago in San Francisco, CA -
- Remote IPv4 - - 69.100.123.11 -
- Remote IPv6 - - 2001:0db8:85a3:0000:0000:8a2e:0370:7334 -
- Transfer - - 4.43 GB up, 1.23 GB down -
- Client version - - v1.01 for macOS/arm64 -
- OS version - - macOS 13.4.1 -
- Machine type - - Macbook Pro -
+ <%= @device.actor.name %> + + + + <.vertical_table_row> + <:label>First Seen + <:value>TODO + + <.vertical_table_row> + <:label>Last Seen + <:value>TODO + + <.vertical_table_row> + <:label>Remote IPv4 + <:value><%= @device.ipv4 %> + + <.vertical_table_row> + <:label>Remote IPv6 + <:value><%= @device.ipv6 %> + + <.vertical_table_row> + <:label>Transfer + <:value>TODO + + <.vertical_table_row> + <:label>Client Version + <:value>TODO + + <.vertical_table_row> + <:label>OS Version + <:value>TODO + + <.vertical_table_row> + <:label>Machine Type + <:value>TODO + +
<.header> diff --git a/elixir/apps/web/lib/web/live/users/edit.ex b/elixir/apps/web/lib/web/live/users/edit.ex deleted file mode 100644 index 3d455aeaa..000000000 --- a/elixir/apps/web/lib/web/live/users/edit.ex +++ /dev/null @@ -1,128 +0,0 @@ -defmodule Web.Users.Edit do - use Web, :live_view - - def render(assigns) do - ~H""" - <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> - <.breadcrumb path={~p"/#{@account}/actors"}>Users - <.breadcrumb path={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"}> - Jamil Bou Kheir - - <.breadcrumb path={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89/edit"}> - Edit - - - <.header> - <:title> - Editing user Bou Kheir, Jamil - - - -
-
-

Edit user details

-
-
-
- <.label for="first-name"> - First Name - - -
-
- <.label for="last-name"> - Last Name - - -
-
- <.label for="email"> - Email - - -

- We'll send a confirmation email to both the current email address and the updated one to confirm the change. -

-
-
- <.label for="confirm-email"> - Confirm email - - -
-
- <.label for="user-role"> - Role - - -

- Select Admin to make this user an administrator of your organization. -

-
-
- <.label for="user-groups"> - Groups - - -

- Select one or more groups to allow this user access to resources. -

-
-
-
- -
-
-
-
- """ - end -end diff --git a/elixir/apps/web/lib/web/live/users/index.ex b/elixir/apps/web/lib/web/live/users/index.ex deleted file mode 100644 index f239b56f2..000000000 --- a/elixir/apps/web/lib/web/live/users/index.ex +++ /dev/null @@ -1,278 +0,0 @@ -defmodule Web.Users.Index do - use Web, :live_view - - def render(assigns) do - ~H""" - <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> - <.breadcrumb path={~p"/#{@account}/actors"}>Users - - <.header> - <:title> - All users - - <:actions> - <.add_button navigate={~p"/#{@account}/actors/new"}> - Add a new user - - - - -
-
-
-
- -
-
- <.icon name="hero-magnifying-glass" class="w-5 h-5 text-gray-500 dark:text-gray-400" /> -
- -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - Actions -
- <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - Bou Kheir, Jamil - - - email:jamil@firezone.dev,okta:jamil@firezone.dev - Admin, Engineering, 3 more...Today at 2:30 pm - - -
- <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - Dryga, Andrew - - - email:a@firezone.dev,okta:andrew.dryga@firezone.dev - Admin, DevOps, Engineering, 3 more...Just now - - -
- <.link - navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"} - class="font-medium text-blue-600 dark:text-blue-500 hover:underline" - > - Steinberg, Gabriel - - - email:a@firezone.dev,okta:andrew.dryga@firezone.dev - DevOps, IT, SecurityA month ago - - -
-
- <.paginator page={3} total_pages={100} collection_base_path={~p"/#{@account}/actors"} /> -
- """ - end -end diff --git a/elixir/apps/web/lib/web/live/users/show.ex b/elixir/apps/web/lib/web/live/users/show.ex deleted file mode 100644 index 91f49adc9..000000000 --- a/elixir/apps/web/lib/web/live/users/show.ex +++ /dev/null @@ -1,126 +0,0 @@ -defmodule Web.Users.Show do - use Web, :live_view - - def render(assigns) do - ~H""" - <.breadcrumbs home_path={~p"/#{@account}/dashboard"}> - <.breadcrumb path={~p"/#{@account}/actors"}>Users - <.breadcrumb path={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89"}> - Jamil Bou Kheir - - - <.header> - <:title> - Viewing User Bou Kheir, Jamil - - <:actions> - <.edit_button navigate={~p"/#{@account}/actors/DF43E951-7DFB-4921-8F7F-BF0F8D31FA89/edit"}> - Edit user - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- First name - - Steve -
- Last name - - Johnson -
- Source - - Manually created by - Jamil Bou Kheir - on May 3rd, 2023. -
- Email - - steve@tesla.com - Verified -
- Role - - Admin -
- Groups - - <.link - navigate={~p"/#{@account}/groups/55DDA8CB-69A7-48FC-9048-639021C205A2"} - class="text-blue-600 hover:underline" - > - Engineering - -
- Last active - - 1 hour ago -
-
- - <.header> - <:title> - Danger zone - - <:actions> - <.delete_button> - Delete user - - - - """ - end -end diff --git a/elixir/apps/web/lib/web/router.ex b/elixir/apps/web/lib/web/router.ex index 45430f6e1..48b2e43e6 100644 --- a/elixir/apps/web/lib/web/router.ex +++ b/elixir/apps/web/lib/web/router.ex @@ -100,7 +100,7 @@ defmodule Web.Router do ] do live "/dashboard", Dashboard - scope "/actors", Users do + scope "/actors", Actors do live "/", Index live "/new", New live "/:id/edit", Edit