mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
chore(portal): DRY live table error handling and handle errors via page reloads (#4205)
I also added whole bunch of tests for the live tables. Closes #4189
This commit is contained in:
@@ -26,20 +26,14 @@ defmodule Web.Actors.Index do
|
||||
def handle_actors_update!(socket, list_opts) do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:last_seen_at, identities: :provider])
|
||||
|
||||
with {:ok, actors, metadata} <- Actors.list_actors(socket.assigns.subject, list_opts) do
|
||||
{:ok, actor_groups} = Actors.peek_actor_groups(actors, 3, socket.assigns.subject)
|
||||
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata,
|
||||
actor_groups: actor_groups
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
with {:ok, actors, metadata} <- Actors.list_actors(socket.assigns.subject, list_opts),
|
||||
{:ok, actor_groups} <- Actors.peek_actor_groups(actors, 3, socket.assigns.subject) do
|
||||
{:ok,
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata,
|
||||
actor_groups: actor_groups
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -59,16 +59,11 @@ defmodule Web.Actors.Show do
|
||||
|
||||
with {:ok, identities, metadata} <-
|
||||
Auth.list_identities_for(socket.assigns.actor, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
identities: identities,
|
||||
identities_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
identities: identities,
|
||||
identities_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -82,16 +77,11 @@ defmodule Web.Actors.Show do
|
||||
|
||||
with {:ok, tokens, metadata} <-
|
||||
Tokens.list_tokens_for(socket.assigns.actor, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
tokens: tokens,
|
||||
tokens_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
tokens: tokens,
|
||||
tokens_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,16 +90,11 @@ defmodule Web.Actors.Show do
|
||||
|
||||
with {:ok, clients, metadata} <-
|
||||
Clients.list_clients_for(socket.assigns.actor, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
clients: clients,
|
||||
clients_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
clients: clients,
|
||||
clients_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -123,16 +108,11 @@ defmodule Web.Actors.Show do
|
||||
|
||||
with {:ok, flows, metadata} <-
|
||||
Flows.list_flows_for(socket.assigns.actor, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -30,16 +30,11 @@ defmodule Web.Clients.Index do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:actor, :online?])
|
||||
|
||||
with {:ok, clients, metadata} <- Clients.list_clients(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
clients: clients,
|
||||
clients_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
clients: clients,
|
||||
clients_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -47,16 +47,11 @@ defmodule Web.Clients.Show do
|
||||
|
||||
with {:ok, flows, metadata} <-
|
||||
Flows.list_flows_for(socket.assigns.client, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -48,16 +48,11 @@ defmodule Web.Groups.EditActors do
|
||||
list_opts = Keyword.put(list_opts, :preload, identities: :provider)
|
||||
|
||||
with {:ok, actors, metadata} <- Actors.list_actors(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -26,20 +26,14 @@ defmodule Web.Groups.Index do
|
||||
def handle_groups_update!(socket, list_opts) do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:provider, created_by_identity: [:actor]])
|
||||
|
||||
with {:ok, groups, metadata} <- Actors.list_groups(socket.assigns.subject, list_opts) do
|
||||
{:ok, group_actors} = Actors.peek_group_actors(groups, 3, socket.assigns.subject)
|
||||
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata,
|
||||
group_actors: group_actors
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
with {:ok, groups, metadata} <- Actors.list_groups(socket.assigns.subject, list_opts),
|
||||
{:ok, group_actors} <- Actors.peek_group_actors(groups, 3, socket.assigns.subject) do
|
||||
{:ok,
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata,
|
||||
group_actors: group_actors
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -50,16 +50,11 @@ defmodule Web.Groups.Show do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:last_seen_at, identities: :provider])
|
||||
|
||||
with {:ok, actors, metadata} <- Actors.list_actors(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
actors: actors,
|
||||
actors_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,16 +62,11 @@ defmodule Web.Groups.Show do
|
||||
list_opts = Keyword.put(list_opts, :preload, :resource)
|
||||
|
||||
with {:ok, policies, metadata} <- Policies.list_policies(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -29,16 +29,11 @@ defmodule Web.Policies.Index do
|
||||
list_opts = Keyword.put(list_opts, :preload, actor_group: [:provider], resource: [])
|
||||
|
||||
with {:ok, policies, metadata} <- Policies.list_policies(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -45,16 +45,11 @@ defmodule Web.Policies.Show do
|
||||
|
||||
with {:ok, flows, metadata} <-
|
||||
Flows.list_flows_for(socket.assigns.policy, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -33,16 +33,11 @@ defmodule Web.RelayGroups.Index do
|
||||
list_opts = Keyword.put(list_opts, :preload, relays: [:online?])
|
||||
|
||||
with {:ok, groups, metadata} <- Relays.list_groups(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -49,16 +49,11 @@ defmodule Web.RelayGroups.Show do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:online?])
|
||||
|
||||
with {:ok, relays, metadata} <- Relays.list_relays(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
relays: relays,
|
||||
relays_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
relays: relays,
|
||||
relays_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -31,21 +31,15 @@ defmodule Web.Resources.Index do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:gateway_groups])
|
||||
|
||||
with {:ok, resources, metadata} <-
|
||||
Resources.list_resources(socket.assigns.subject, list_opts) do
|
||||
{:ok, resource_actor_groups_peek} =
|
||||
Resources.peek_resource_actor_groups(resources, 3, socket.assigns.subject)
|
||||
|
||||
assign(socket,
|
||||
resources: resources,
|
||||
resource_actor_groups_peek: resource_actor_groups_peek,
|
||||
resources_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
Resources.list_resources(socket.assigns.subject, list_opts),
|
||||
{:ok, resource_actor_groups_peek} <-
|
||||
Resources.peek_resource_actor_groups(resources, 3, socket.assigns.subject) do
|
||||
{:ok,
|
||||
assign(socket,
|
||||
resources: resources,
|
||||
resource_actor_groups_peek: resource_actor_groups_peek,
|
||||
resources_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -55,16 +55,11 @@ defmodule Web.Resources.Show do
|
||||
list_opts = Keyword.put(list_opts, :preload, actor_group: [:provider], resource: [])
|
||||
|
||||
with {:ok, policies, metadata} <- Policies.list_policies(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
policies: policies,
|
||||
policies_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -78,16 +73,11 @@ defmodule Web.Resources.Show do
|
||||
|
||||
with {:ok, flows, metadata} <-
|
||||
Flows.list_flows_for(socket.assigns.resource, socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
flows: flows,
|
||||
flows_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -36,16 +36,11 @@ defmodule Web.Settings.IdentityProviders.Index do
|
||||
|
||||
def handle_providers_update!(socket, list_opts) do
|
||||
with {:ok, providers, metadata} <- Auth.list_providers(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
providers: providers,
|
||||
providers_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
providers: providers,
|
||||
providers_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -41,16 +41,11 @@ defmodule Web.Sites.Gateways.Index do
|
||||
list_opts = Keyword.put(list_opts, :preload, [:online?])
|
||||
|
||||
with {:ok, gateways, metadata} <- Gateways.list_gateways(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
gateways: gateways,
|
||||
gateways_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
gateways: gateways,
|
||||
gateways_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -31,16 +31,11 @@ defmodule Web.Sites.Index do
|
||||
|
||||
with {:ok, groups, metadata} <-
|
||||
Gateways.list_groups(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
groups: groups,
|
||||
groups_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -63,36 +63,25 @@ defmodule Web.Sites.Show do
|
||||
end)
|
||||
|
||||
with {:ok, gateways, metadata} <- Gateways.list_gateways(socket.assigns.subject, list_opts) do
|
||||
assign(socket,
|
||||
gateways: gateways,
|
||||
gateways_metadata: metadata
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
{:ok,
|
||||
assign(socket,
|
||||
gateways: gateways,
|
||||
gateways_metadata: metadata
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_resources_update!(socket, list_opts) do
|
||||
with {:ok, resources, metadata} <-
|
||||
Resources.list_resources(socket.assigns.subject, list_opts) do
|
||||
{:ok, resource_actor_groups_peek} =
|
||||
Resources.peek_resource_actor_groups(resources, 3, socket.assigns.subject)
|
||||
|
||||
assign(socket,
|
||||
resources: resources,
|
||||
resources_metadata: metadata,
|
||||
resource_actor_groups_peek: resource_actor_groups_peek
|
||||
)
|
||||
else
|
||||
{:error, :invalid_cursor} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:unknown_filter, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_type, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, {:invalid_value, _metadata}} -> raise Web.LiveErrors.InvalidRequestError
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
Resources.list_resources(socket.assigns.subject, list_opts),
|
||||
{:ok, resource_actor_groups_peek} <-
|
||||
Resources.peek_resource_actor_groups(resources, 3, socket.assigns.subject) do
|
||||
{:ok,
|
||||
assign(socket,
|
||||
resources: resources,
|
||||
resources_metadata: metadata,
|
||||
resource_actor_groups_peek: resource_actor_groups_peek
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -82,7 +82,13 @@ defmodule Web.LiveTable do
|
||||
|
||||
defp resource_filter(assigns) do
|
||||
~H"""
|
||||
<.form id={"#{@live_table_id}-filters"} for={@form} phx-change="filter" phx-debounce="100">
|
||||
<.form
|
||||
:if={@filters != []}
|
||||
id={"#{@live_table_id}-filters"}
|
||||
for={@form}
|
||||
phx-change="filter"
|
||||
phx-debounce="100"
|
||||
>
|
||||
<.input type="hidden" name="table_id" value={@live_table_id} />
|
||||
|
||||
<div
|
||||
@@ -423,7 +429,11 @@ defmodule Web.LiveTable do
|
||||
def reload_live_table!(socket, id) do
|
||||
callback = Map.fetch!(socket.assigns.callback_by_table_id, id)
|
||||
list_opts = Map.get(socket.assigns[:list_opts_by_table_id] || %{}, id, [])
|
||||
callback.(socket, list_opts)
|
||||
|
||||
case callback.(socket, list_opts) do
|
||||
{:error, _reason} -> push_navigate(socket, to: socket.assigns.uri)
|
||||
{:ok, socket} -> socket
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -457,31 +467,48 @@ defmodule Web.LiveTable do
|
||||
order_by: List.wrap(order_by)
|
||||
]
|
||||
|
||||
socket
|
||||
|> maybe_apply_callback(id, list_opts)
|
||||
|> assign(
|
||||
filter_form_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:filter_form_by_table_id,
|
||||
filter_to_form(filter, id)
|
||||
),
|
||||
order_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:order_by_table_id,
|
||||
order_by
|
||||
),
|
||||
list_opts_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:list_opts_by_table_id,
|
||||
list_opts
|
||||
case maybe_apply_callback(socket, id, list_opts) do
|
||||
{:ok, socket} ->
|
||||
socket
|
||||
|> assign(
|
||||
filter_form_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:filter_form_by_table_id,
|
||||
filter_to_form(filter, id)
|
||||
),
|
||||
order_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:order_by_table_id,
|
||||
order_by
|
||||
),
|
||||
list_opts_by_table_id:
|
||||
put_table_state(
|
||||
socket,
|
||||
id,
|
||||
:list_opts_by_table_id,
|
||||
list_opts
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
{:error, :invalid_cursor} ->
|
||||
raise Web.LiveErrors.InvalidRequestError
|
||||
|
||||
{:error, {:unknown_filter, _metadata}} ->
|
||||
raise Web.LiveErrors.InvalidRequestError
|
||||
|
||||
{:error, {:invalid_type, _metadata}} ->
|
||||
raise Web.LiveErrors.InvalidRequestError
|
||||
|
||||
{:error, {:invalid_value, _metadata}} ->
|
||||
raise Web.LiveErrors.InvalidRequestError
|
||||
|
||||
{:error, _reason} ->
|
||||
raise Web.LiveErrors.NotFoundError
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_apply_callback(socket, id, list_opts) do
|
||||
@@ -491,7 +518,7 @@ defmodule Web.LiveTable do
|
||||
callback = Map.fetch!(socket.assigns.callback_by_table_id, id)
|
||||
callback.(socket, list_opts)
|
||||
else
|
||||
socket
|
||||
{:ok, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -529,7 +556,8 @@ defmodule Web.LiveTable do
|
||||
ArgumentError -> []
|
||||
end
|
||||
|
||||
defp filter_to_form(filter, as) do
|
||||
@doc false
|
||||
def filter_to_form(filter, as) do
|
||||
# Note: we don't support nesting, :and or :where on the UI yet
|
||||
for {key, value} <- filter, into: %{} do
|
||||
{Atom.to_string(key), value}
|
||||
|
||||
734
elixir/apps/web/test/web/live_table_test.exs
Normal file
734
elixir/apps/web/test/web/live_table_test.exs
Normal file
@@ -0,0 +1,734 @@
|
||||
defmodule Web.LiveTableTest do
|
||||
use Web.ConnCase, async: true
|
||||
import Web.LiveTable
|
||||
|
||||
describe "<.live_table /> component" do
|
||||
setup do
|
||||
assigns = %{
|
||||
id: "table-id",
|
||||
filters: [],
|
||||
filter: filter_to_form(%{}, "table-id"),
|
||||
ordered_by: {:assoc, :name},
|
||||
metadata: %{
|
||||
previous_page_cursor: nil,
|
||||
next_page_cursor: nil,
|
||||
limit: 10,
|
||||
count: 1
|
||||
},
|
||||
col: [
|
||||
%{
|
||||
label: "name",
|
||||
field: {:assoc, :name},
|
||||
inner_block: fn _col, row ->
|
||||
row
|
||||
end
|
||||
}
|
||||
],
|
||||
rows: ["foo"]
|
||||
}
|
||||
|
||||
%{assigns: assigns}
|
||||
end
|
||||
|
||||
test "renders a data table", %{assigns: assigns} do
|
||||
html = render_component(&live_table/1, assigns)
|
||||
|
||||
assert html
|
||||
|> Floki.find("table")
|
||||
|> Floki.attribute("id") == ["table-id"]
|
||||
|
||||
assert html
|
||||
|> Floki.find("table thead")
|
||||
|> Floki.attribute("id") == ["table-id-header"]
|
||||
|
||||
assert html
|
||||
|> Floki.find("th")
|
||||
|> Floki.text() =~ "name"
|
||||
|
||||
assert html
|
||||
|> Floki.find("table tbody")
|
||||
|> Floki.attribute("id") == ["table-id-rows"]
|
||||
|
||||
assert html
|
||||
|> Floki.find("td")
|
||||
|> Floki.text() =~ "foo"
|
||||
end
|
||||
|
||||
test "renders fulltext search filter", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :search,
|
||||
title: "Query",
|
||||
type: {:string, :websearch}
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{search: "foo"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
input = Floki.find(form, "input[type=text]")
|
||||
assert Floki.attribute(input, "id") == ["table-id_search"]
|
||||
assert Floki.attribute(input, "name") == ["table-id[search]"]
|
||||
assert Floki.attribute(input, "placeholder") == ["Search by Query"]
|
||||
assert Floki.attribute(input, "value") == ["foo"]
|
||||
end
|
||||
|
||||
test "renders email filter", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :email,
|
||||
title: "Email",
|
||||
type: {:string, :email}
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{email: "foo@bar.com"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
input = Floki.find(form, "input[type=text]")
|
||||
assert Floki.attribute(input, "id") == ["table-id_email"]
|
||||
assert Floki.attribute(input, "name") == ["table-id[email]"]
|
||||
assert Floki.attribute(input, "placeholder") == ["Search by Email"]
|
||||
assert Floki.attribute(input, "value") == ["foo@bar.com"]
|
||||
end
|
||||
|
||||
test "renders UUID dropdown filter", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :id,
|
||||
title: "ID",
|
||||
type: {:string, :uuid},
|
||||
values: [
|
||||
{"group1", [{"One", "1"}]},
|
||||
{"group1", [{"Two", "2"}]},
|
||||
{nil, [{"Three", "3"}]}
|
||||
]
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{id: "1"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
select = Floki.find(form, "select")
|
||||
assert Floki.attribute(select, "id") == ["table-id_id"]
|
||||
assert Floki.attribute(select, "name") == ["table-id[id]"]
|
||||
|
||||
assert select |> List.first() |> elem(2) == [
|
||||
{"option", [{"value", ""}], ["For any ID"]},
|
||||
{"optgroup", [{"label", "group1"}],
|
||||
[{"option", [{"selected", "selected"}, {"value", "1"}], ["One"]}]},
|
||||
{"optgroup", [{"label", "group1"}], [{"option", [{"value", "2"}], ["Two"]}]},
|
||||
{"option", [{"value", "3"}], ["Three"]}
|
||||
]
|
||||
end
|
||||
|
||||
test "renders radio buttons for select from up to 5 values", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :btn,
|
||||
title: "Button",
|
||||
type: :string,
|
||||
values: [
|
||||
{"One", "1"},
|
||||
{"Two", "2"}
|
||||
]
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{id: "1"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
radio = Floki.find(form, "input[type=radio]")
|
||||
|
||||
assert Floki.attribute(radio, "id") == [
|
||||
"table-id-btn-__all__",
|
||||
"table-id-btn-1",
|
||||
"table-id-btn-2"
|
||||
]
|
||||
|
||||
assert Floki.attribute(radio, "name") == [
|
||||
"_reset:table-id[btn]",
|
||||
"table-id[btn]",
|
||||
"table-id[btn]"
|
||||
]
|
||||
|
||||
assert Floki.attribute(radio, "value") == [
|
||||
"true",
|
||||
"1",
|
||||
"2"
|
||||
]
|
||||
end
|
||||
|
||||
test "renders checkbox-like buttons for multi-select from up to 5 values", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :btn,
|
||||
title: "Button",
|
||||
type: {:list, :string},
|
||||
values: [
|
||||
{"One", "1"},
|
||||
{"Two", "2"}
|
||||
]
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{id: "1"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
radio = Floki.find(form, "input[type=checkbox]")
|
||||
|
||||
assert Floki.attribute(radio, "id") == [
|
||||
"table-id-btn-__all__",
|
||||
"table-id-btn-1",
|
||||
"table-id-btn-2"
|
||||
]
|
||||
|
||||
assert Floki.attribute(radio, "name") == [
|
||||
"_reset:table-id[btn]",
|
||||
"table-id[btn][]",
|
||||
"table-id[btn][]"
|
||||
]
|
||||
|
||||
assert Floki.attribute(radio, "value") == [
|
||||
"value",
|
||||
"1",
|
||||
"2"
|
||||
]
|
||||
end
|
||||
|
||||
test "renders value dropdown when there are more than 5 values", %{assigns: assigns} do
|
||||
assigns = %{
|
||||
assigns
|
||||
| filters: [
|
||||
%Domain.Repo.Filter{
|
||||
name: :select,
|
||||
title: "Select",
|
||||
type: :string,
|
||||
values: [
|
||||
{"One", "1"},
|
||||
{"Two", "2"},
|
||||
{"Three", "3"},
|
||||
{"Four", "4"},
|
||||
{"Five", "5"},
|
||||
{"Six", "6"}
|
||||
]
|
||||
}
|
||||
],
|
||||
filter: filter_to_form(%{id: "1"}, "table-id")
|
||||
}
|
||||
|
||||
form =
|
||||
render_component(&live_table/1, assigns)
|
||||
|> Floki.find("form")
|
||||
|
||||
assert Floki.attribute(form, "id") == ["table-id-filters"]
|
||||
assert Floki.attribute(form, "phx-change") == ["filter"]
|
||||
|
||||
input = Floki.find(form, "input[type=hidden]")
|
||||
assert Floki.attribute(input, "name") == ["table_id"]
|
||||
assert Floki.attribute(input, "value") == ["table-id"]
|
||||
|
||||
select = Floki.find(form, "select")
|
||||
assert Floki.attribute(select, "id") == ["table-id_select"]
|
||||
assert Floki.attribute(select, "name") == ["table-id[select]"]
|
||||
|
||||
assert select |> List.first() |> elem(2) == [
|
||||
{"option", [{"value", ""}], ["For any Select"]},
|
||||
{"optgroup", [{"label", "Select"}],
|
||||
[
|
||||
{"option", [{"value", "1"}], ["One"]},
|
||||
{"option", [{"value", "2"}], ["Two"]},
|
||||
{"option", [{"value", "3"}], ["Three"]},
|
||||
{"option", [{"value", "4"}], ["Four"]},
|
||||
{"option", [{"value", "5"}], ["Five"]},
|
||||
{"option", [{"value", "6"}], ["Six"]}
|
||||
]}
|
||||
]
|
||||
end
|
||||
|
||||
test "renders ordering buttons", %{assigns: assigns} do
|
||||
# default order when it's unset
|
||||
html = render_component(&live_table/1, assigns)
|
||||
order_button = Floki.find(html, "th button")
|
||||
assert Floki.attribute(order_button, "phx-click") == ["order_by"]
|
||||
assert Floki.attribute(order_button, "phx-value-table_id") == ["table-id"]
|
||||
assert Floki.attribute(order_button, "phx-value-order_by") == ["assoc:asc:name"]
|
||||
|
||||
# current order if it's set
|
||||
assigns = %{assigns | ordered_by: {:assoc, :desc, :name}}
|
||||
html = render_component(&live_table/1, assigns)
|
||||
order_button = Floki.find(html, "th button")
|
||||
assert Floki.attribute(order_button, "phx-value-order_by") == ["assoc:desc:name"]
|
||||
end
|
||||
|
||||
test "renders page size and total count", %{assigns: assigns} do
|
||||
assert render_component(&live_table/1, assigns)
|
||||
|> Floki.find("nav > span")
|
||||
|> Floki.text()
|
||||
|> String.replace(~r/[\s]+/, " ") =~ "Showing 1 of 1"
|
||||
|
||||
assert render_component(&live_table/1, %{
|
||||
assigns
|
||||
| metadata: %{assigns.metadata | count: 10, limit: 100}
|
||||
})
|
||||
|> Floki.find("nav > span")
|
||||
|> Floki.text()
|
||||
|> String.replace(~r/[\s]+/, " ") =~ "Showing 10 of 10"
|
||||
|
||||
assert render_component(&live_table/1, %{
|
||||
assigns
|
||||
| metadata: %{assigns.metadata | count: 100, limit: 10}
|
||||
})
|
||||
|> Floki.find("nav > span")
|
||||
|> Floki.text()
|
||||
|> String.replace(~r/[\s]+/, " ") =~ "Showing 10 of 100"
|
||||
end
|
||||
|
||||
test "renders pagination buttons", %{assigns: assigns} do
|
||||
html = render_component(&live_table/1, assigns)
|
||||
|
||||
assert html
|
||||
|> Floki.find("nav button")
|
||||
|> Floki.attribute("disabled") == ["disabled", "disabled"]
|
||||
|
||||
assigns = %{assigns | metadata: %{assigns.metadata | next_page_cursor: "next_cursor"}}
|
||||
html = render_component(&live_table/1, assigns)
|
||||
|
||||
assert html
|
||||
|> Floki.find("nav button")
|
||||
|> Floki.attribute("disabled") == ["disabled"]
|
||||
|
||||
enabled_button = Floki.find(html, "nav button:not([disabled])")
|
||||
assert Floki.attribute(enabled_button, "phx-click") == ["paginate"]
|
||||
assert Floki.attribute(enabled_button, "phx-value-cursor") == ["next_cursor"]
|
||||
assert Floki.attribute(enabled_button, "phx-value-table_id") == ["table-id"]
|
||||
|
||||
assigns = %{assigns | metadata: %{assigns.metadata | previous_page_cursor: "prev_cursor"}}
|
||||
html = render_component(&live_table/1, assigns)
|
||||
|
||||
assert html
|
||||
|> Floki.find("nav button")
|
||||
|> Floki.attribute("disabled") == []
|
||||
|
||||
enabled_button = Floki.find(html, "nav button:not([disabled])")
|
||||
assert "prev_cursor" in Floki.attribute(enabled_button, "phx-value-cursor")
|
||||
end
|
||||
end
|
||||
|
||||
describe "assign_live_table/3" do
|
||||
setup do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
socket = %Phoenix.LiveView.Socket{assigns: %{subject: subject, __changed__: %{}}}
|
||||
%{socket: socket}
|
||||
end
|
||||
|
||||
test "persists live table state in the socket", %{socket: socket} do
|
||||
assert %{
|
||||
assigns: %{
|
||||
__changed__: %{
|
||||
live_table_ids: true,
|
||||
callback_by_table_id: true,
|
||||
sortable_fields_by_table_id: true,
|
||||
filters_by_table_id: true,
|
||||
enforced_filters_by_table_id: true,
|
||||
limit_by_table_id: true
|
||||
},
|
||||
live_table_ids: ["table-id"],
|
||||
callback_by_table_id: %{"table-id" => _fun},
|
||||
sortable_fields_by_table_id: %{"table-id" => [actors: :name]},
|
||||
filters_by_table_id: %{"table-id" => []},
|
||||
enforced_filters_by_table_id: %{},
|
||||
limit_by_table_id: %{}
|
||||
}
|
||||
} =
|
||||
assign_live_table(socket, "table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
assert %{
|
||||
assigns: %{
|
||||
__changed__: %{
|
||||
live_table_ids: true,
|
||||
callback_by_table_id: true,
|
||||
sortable_fields_by_table_id: true,
|
||||
filters_by_table_id: true,
|
||||
enforced_filters_by_table_id: true,
|
||||
limit_by_table_id: true
|
||||
},
|
||||
live_table_ids: ["table-id"],
|
||||
callback_by_table_id: %{"table-id" => _fun},
|
||||
sortable_fields_by_table_id: %{"table-id" => [actors: :name]},
|
||||
filters_by_table_id: %{"table-id" => []},
|
||||
enforced_filters_by_table_id: %{"table-id" => [name: "foo"]},
|
||||
limit_by_table_id: %{"table-id" => 11}
|
||||
}
|
||||
} =
|
||||
assign_live_table(socket, "table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
enforce_filters: [
|
||||
{:name, "foo"}
|
||||
],
|
||||
hide_filters: [:email],
|
||||
limit: 11,
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "reload_live_table!/2" do
|
||||
test "reloads the live table" do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{subject: subject, __changed__: %{}}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
assert %{
|
||||
private: %{list_opts: []}
|
||||
} = reload_live_table!(socket, "table-id")
|
||||
end
|
||||
|
||||
test "reloads whole page on errors" do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{subject: subject, uri: "/current_uri", __changed__: %{}}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn _socket, _list_opts -> {:error, :not_found} end
|
||||
)
|
||||
|
||||
assert %{
|
||||
redirected: {:live, :redirect, %{kind: :push, to: "/current_uri"}}
|
||||
} = reload_live_table!(socket, "table-id")
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_live_tables_params/3" do
|
||||
setup do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
test_pid = self()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{subject: subject, __changed__: %{}}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
send(test_pid, {:callback, socket, list_opts})
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
%{socket: socket}
|
||||
end
|
||||
|
||||
test "assigns the live table data from callbacks", %{socket: socket} do
|
||||
assert %{
|
||||
assigns: %{
|
||||
uri: "/actors"
|
||||
},
|
||||
private: %{
|
||||
list_opts: [
|
||||
page: [limit: 25],
|
||||
filter: [],
|
||||
order_by: []
|
||||
]
|
||||
}
|
||||
} = handle_live_tables_params(socket, %{}, "/actors")
|
||||
|
||||
assert %{
|
||||
assigns: %{
|
||||
uri: "/actors"
|
||||
},
|
||||
private: %{
|
||||
list_opts: [
|
||||
page: [cursor: "next_page", limit: 25],
|
||||
filter: [{:name, "foo"}],
|
||||
order_by: [{:actors, :asc, :name}]
|
||||
]
|
||||
}
|
||||
} =
|
||||
handle_live_tables_params(
|
||||
socket,
|
||||
%{
|
||||
"table-id_cursor" => "next_page",
|
||||
"table-id_filter" => %{"name" => "foo"},
|
||||
"table-id_order_by" => "actors:asc:name"
|
||||
},
|
||||
"/actors"
|
||||
)
|
||||
end
|
||||
|
||||
test "does nothing when list opts are not changed", %{socket: socket} do
|
||||
socket = handle_live_tables_params(socket, %{}, "/actors")
|
||||
assert_receive {:callback, _socket, [page: [limit: 25], filter: [], order_by: []]}
|
||||
|
||||
handle_live_tables_params(socket, %{}, "/actors")
|
||||
refute_receive {:callback, _socket, _list_opts}
|
||||
end
|
||||
|
||||
test "raises if the callback returns an error" do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{subject: subject, uri: "/current_uri", __changed__: %{}}
|
||||
}
|
||||
|
||||
for {reason, exception} <- [
|
||||
{:not_found, Web.LiveErrors.NotFoundError},
|
||||
{:unauthorized, Web.LiveErrors.NotFoundError},
|
||||
{:invalid_cursor, Web.LiveErrors.InvalidRequestError},
|
||||
{{:unknown_filter, []}, Web.LiveErrors.InvalidRequestError},
|
||||
{{:invalid_type, []}, Web.LiveErrors.InvalidRequestError},
|
||||
{{:invalid_value, []}, Web.LiveErrors.InvalidRequestError}
|
||||
] do
|
||||
socket =
|
||||
assign_live_table(socket, "table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn _socket, _list_opts -> {:error, reason} end
|
||||
)
|
||||
|
||||
assert_raise exception, fn ->
|
||||
handle_live_tables_params(socket, %{}, "/foo")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_live_table_event/3 for pagination" do
|
||||
setup do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{
|
||||
subject: subject,
|
||||
uri:
|
||||
"/actors?table-id_cursor=prev_page" <>
|
||||
"&table-id_filter%5Bname%5D=buz" <>
|
||||
"&table-id_order_by=actors%3Aasc%3Aname",
|
||||
__changed__: %{}
|
||||
}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
%{socket: socket}
|
||||
end
|
||||
|
||||
test "updates query parameters with new cursor", %{socket: socket} do
|
||||
assert handle_live_table_event(
|
||||
"paginate",
|
||||
%{"table_id" => "table-id", "cursor" => "very_next_page"},
|
||||
socket
|
||||
)
|
||||
|> fetch_patched_query_params!() == %{
|
||||
"table-id_order_by" => "actors:asc:name",
|
||||
"table-id_cursor" => "very_next_page",
|
||||
"table-id_filter[name]" => "buz"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_live_table_event/3 for filtering" do
|
||||
setup do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{
|
||||
subject: subject,
|
||||
uri:
|
||||
"/actors?table-id_cursor=next_page" <>
|
||||
"&table-id_filter%5Bemail%5D=bar" <>
|
||||
"&table-id_filter%5Bname%5D=buz" <>
|
||||
"&table-id_order_by=actors%3Aasc%3Aname",
|
||||
__changed__: %{}
|
||||
}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
%{socket: socket}
|
||||
end
|
||||
|
||||
test "resets the query parameters with filter value is set to all", %{socket: socket} do
|
||||
assert handle_live_table_event(
|
||||
"filter",
|
||||
%{"table_id" => "table-id", "_target" => ["_reset:table-id", "name"]},
|
||||
socket
|
||||
)
|
||||
|> fetch_patched_query_params!() == %{
|
||||
"table-id_filter[email]" => "bar",
|
||||
"table-id_order_by" => "actors:asc:name"
|
||||
}
|
||||
end
|
||||
|
||||
test "updates query parameters with new filter and resets the cursor", %{socket: socket} do
|
||||
assert handle_live_table_event(
|
||||
"filter",
|
||||
%{"table_id" => "table-id", "table-id" => %{"name" => "foo"}},
|
||||
socket
|
||||
)
|
||||
|> fetch_patched_query_params!() == %{
|
||||
"table-id_filter[name]" => "foo",
|
||||
"table-id_order_by" => "actors:asc:name"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle_live_table_event/3 for ordering" do
|
||||
setup do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
|
||||
socket =
|
||||
%Phoenix.LiveView.Socket{
|
||||
assigns: %{
|
||||
subject: subject,
|
||||
uri:
|
||||
"/actors?table-id_cursor=next_page&table-id_filter%5Bname%5D=bar&table-id_order_by=actors%3Aasc%3Aname",
|
||||
__changed__: %{}
|
||||
}
|
||||
}
|
||||
|> assign_live_table("table-id",
|
||||
query_module: Actors.Actor.Query,
|
||||
sortable_fields: [
|
||||
{:actors, :name}
|
||||
],
|
||||
callback: fn socket, list_opts ->
|
||||
{:ok, %{socket | private: %{list_opts: list_opts}}}
|
||||
end
|
||||
)
|
||||
|
||||
%{socket: socket}
|
||||
end
|
||||
|
||||
test "updates query parameters with reverse order and resets the cursor", %{socket: socket} do
|
||||
assert handle_live_table_event(
|
||||
"order_by",
|
||||
%{"table_id" => "table-id", "order_by" => "actors:desc:name"},
|
||||
socket
|
||||
)
|
||||
|> fetch_patched_query_params!() == %{
|
||||
"table-id_filter[name]" => "bar",
|
||||
"table-id_order_by" => "actors:asc:name"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_patched_query_params!(socket) do
|
||||
assert {:noreply, %{redirected: {:live, :patch, %{kind: :push, to: to}}}} = socket
|
||||
uri = URI.parse(to)
|
||||
URI.decode_query(uri.query)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user