improvement: Top nav resource grouping (#15)

This commit is contained in:
Rebecca Le 2022-05-20 00:22:37 +08:00 committed by GitHub
parent cae33cafbc
commit c050c8c228
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 11 deletions

View file

@ -11,6 +11,8 @@ locals_without_parens = [
polymorphic_tables: 1,
read_actions: 1,
relationship_display_fields: 1,
resource_group: 1,
resource_group_labels: 1,
show?: 1,
show_action: 1,
table_columns: 1,

View file

@ -11,6 +11,12 @@ defmodule AshAdmin.Api do
type: :boolean,
default: false,
doc: "Wether or not this api and its resources should be included in the admin dashboard"
],
resource_group_labels: [
type: :keyword_list,
default: [],
doc:
"Humanized names for each resource group to appear in the admin area. These will be used as labels in the top navigation dropdown. If a key for a group does not appear in this mapping, the label will not be rendered."
]
]
}
@ -36,6 +42,10 @@ defmodule AshAdmin.Api do
Ash.Dsl.Extension.get_opt(api, [:admin], :show?, false, true)
end
def resource_group_labels(api) do
Ash.Dsl.Extension.get_opt(api, [:admin], :resource_group_labels, [], true)
end
defp default_name(api) do
split = api |> Module.split()

View file

@ -46,6 +46,7 @@ defmodule AshAdmin.Components.TopNav do
id={AshAdmin.Api.name(api) <> "_api_nav"}
name={AshAdmin.Api.name(api)}
groups={dropdown_groups(@prefix, @resource, api)}
group_labels={dropdown_group_labels(api)}
/>
{/for}
</div>
@ -131,6 +132,7 @@ defmodule AshAdmin.Components.TopNav do
id={AshAdmin.Api.name(api) <> "_api_nav_drawer"}
name={AshAdmin.Api.name(api)}
groups={dropdown_groups(@prefix, @resource, api)}
group_labels={dropdown_group_labels(api)}
/>
</div>
</div>
@ -139,16 +141,22 @@ defmodule AshAdmin.Components.TopNav do
end
defp dropdown_groups(prefix, current_resource, api) do
[
for resource <- Ash.Api.resources(api) do
%{
text: AshAdmin.Resource.name(resource),
to:
"#{prefix}?api=#{AshAdmin.Api.name(api)}&resource=#{AshAdmin.Resource.name(resource)}",
active: resource == current_resource
}
end
]
for resource <- Ash.Api.resources(api) do
%{
text: AshAdmin.Resource.name(resource),
to:
"#{prefix}?api=#{AshAdmin.Api.name(api)}&resource=#{AshAdmin.Resource.name(resource)}",
active: resource == current_resource,
group: AshAdmin.Resource.resource_group(resource)
}
end
|> Enum.group_by(fn resource -> resource.group end)
|> Enum.sort_by(fn {label, _items} -> label || "_____always_put_me_last" end)
|> Keyword.values()
end
defp dropdown_group_labels(api) do
AshAdmin.Api.resource_group_labels(api)
end
def handle_event("collapse_nav", _, socket) do

View file

@ -6,6 +6,7 @@ defmodule AshAdmin.Components.TopNav.DrawerDropdown do
prop(name, :string, required: true)
prop(groups, :list, required: true)
prop(group_labels, :keyword, required: false)
data(open, :boolean, default: false)

View file

@ -6,6 +6,7 @@ defmodule AshAdmin.Components.TopNav.Dropdown do
prop(name, :string, required: true)
prop(groups, :list, required: true)
prop(group_labels, :keyword, required: false)
prop(active, :boolean, required: true)
prop(class, :css_class)
@ -64,6 +65,7 @@ defmodule AshAdmin.Components.TopNav.Dropdown do
aria-orientation="vertical"
aria-labelledby={"#{@id}_dropown"}
>
<.group_label item={hd(group)} group_labels={@group_labels} />
{#for link <- group}
<LiveRedirect
to={link.to}
@ -86,6 +88,26 @@ defmodule AshAdmin.Components.TopNav.Dropdown do
"""
end
defp group_label(assigns) do
assigns = Map.put(assigns, :label_text, group_label_text(assigns))
~F"""
{#if @label_text}
<span class="block px-4 py-2 text-xs text-gray-400 font-semibold italic">{@label_text}</span>
{/if}
"""
end
# No labels specified for the whole dropdown
defp group_label_text(assigns) when not is_map_key(assigns, :group_labels), do: nil
defp group_label_text(%{group_labels: []}), do: nil
# No label specified for this dropdown group
defp group_label_text(%{item: item}) when not is_map_key(item, :group), do: nil
# Maybe a label to display!
defp group_label_text(assigns), do: Keyword.get(assigns.group_labels, assigns.item.group)
def handle_event("close", _, socket) do
{:noreply, assign(socket, :open, false)}
end

View file

@ -17,6 +17,8 @@ defmodule AshAdmin.Helpers do
Plug.Conn.Query.encode(Map.merge(socket_params || %{}, Enum.into(new_params, %{})))
end
def to_name(:id), do: "ID"
def to_name(name) do
name
|> to_string()

View file

@ -73,6 +73,10 @@ defmodule AshAdmin.Resource do
relationship_display_fields: [
type: {:list, :atom},
doc: "The list of attributes to render when it's shown as a relationship on a datatable"
],
resource_group: [
type: :atom,
doc: "A group for the resource to appear in, in the top resource dropdown."
]
]
}
@ -126,6 +130,10 @@ defmodule AshAdmin.Resource do
|> List.last()
end
def resource_group(resource) do
Ash.Dsl.Extension.get_opt(resource, [:admin], :resource_group, nil, true)
end
def actor?(resource) do
Ash.Dsl.Extension.get_opt(resource, [:admin], :actor?, false, true)
end

File diff suppressed because one or more lines are too long