defmodule AshHqWeb.Components.DocSidebar do
@moduledoc "The left sidebar of the docs pages"
use Surface.Component
alias AshHqWeb.DocRoutes
alias Surface.Components.LivePatch
prop class, :css_class, default: ""
prop libraries, :list, required: true
prop extension, :any, default: nil
prop guide, :any, default: nil
prop library, :any, default: nil
prop library_version, :any, default: nil
prop selected_versions, :map, default: %{}
prop id, :string, required: true
prop dsl, :any, required: true
prop module, :any, required: true
prop add_version, :event, required: true
prop remove_version, :event, required: true
prop change_version, :event, required: true
@spec render(any) :: Phoenix.LiveView.Rendered.t()
def render(assigns) do
~F"""
"""
end
defp has_selected_guide?(guides_by_library, guide_id) do
Enum.any?(guides_by_library, fn {_, guides} ->
Enum.any?(guides, &(&1.id == guide_id))
end)
end
defp render_dsls(assigns, dsls, path) do
~F"""
{#for dsl <- Enum.filter(dsls, &(&1.path == path))}
-
{#if Enum.any?(dsls, &List.starts_with?(&1.path, dsl.path ++ [dsl.name]))}
{#if !(@dsl && List.starts_with?(@dsl.path ++ [@dsl.name], path ++ [dsl.name]))}
{/if}
{/if}
{dsl.name}
{render_dsls(assigns, dsls, path ++ [dsl.name])}
{/for}
"""
end
def render_icon(assigns, "Resource") do
~F"""
"""
end
def render_icon(assigns, "Api") do
~F"""
"""
end
def render_icon(assigns, "DataLayer") do
~F"""
"""
end
def render_icon(assigns, "Flow") do
~F"""
"""
end
def render_icon(assigns, "Notifier") do
~F"""
"""
end
def render_icon(assigns, "Registry") do
~F"""
"""
end
def render_icon(assigns, _) do
~F"""
"""
end
@start_guides ["Tutorials", "Topics", "How To", "Misc"]
defp guides_by_category_and_library(libraries, selected_versions) do
libraries =
Enum.filter(libraries, fn library ->
selected_versions[library.id] && selected_versions[library.id] != ""
end)
library_name_to_order =
libraries
|> Enum.sort_by(& &1.order)
|> Enum.map(& &1.display_name)
libraries
|> Enum.flat_map(fn library ->
library.versions
|> Enum.find(&Ash.Resource.loaded?(&1, :guides))
|> case do
nil ->
[]
%{guides: guides} ->
Enum.map(guides, &{&1, library.display_name})
end
end)
|> Enum.group_by(fn {guide, _} ->
guide.category
end)
|> Enum.map(fn {category, guides} ->
guides_by_library =
library_name_to_order
|> Enum.map(fn name ->
{name,
Enum.flat_map(guides, fn {guide, guide_lib_name} ->
if name == guide_lib_name do
[guide]
else
[]
end
end)}
end)
|> Enum.reject(fn {_, guides} ->
Enum.empty?(guides)
end)
{category, guides_by_library}
end)
|> partially_alphabetically_sort(@start_guides, [])
end
defp get_extensions(libraries, selected_versions) do
libraries
|> Enum.filter(fn library ->
selected_versions[library.id] && selected_versions[library.id] != ""
end)
|> Enum.sort_by(& &1.order)
|> Enum.flat_map(fn library ->
case Enum.find(library.versions, &Ash.Resource.loaded?(&1, :extensions)) do
nil ->
[]
version ->
case version.extensions do
[] ->
[]
extensions ->
[{library.display_name, extensions}]
end
end
end)
end
@last_categories ["Errors"]
defp modules_by_category(libraries, selected_versions) do
libraries =
Enum.filter(libraries, fn library ->
selected_versions[library.id] && selected_versions[library.id] != ""
end)
libraries
|> Enum.flat_map(fn library ->
library.versions
|> Enum.find(&Ash.Resource.loaded?(&1, :modules))
|> case do
nil ->
[]
%{modules: modules} ->
modules
end
end)
|> Enum.group_by(fn module ->
module.category
end)
|> Enum.sort_by(fn {category, _} -> category end)
|> Enum.map(fn {category, modules} ->
{category, Enum.sort_by(modules, & &1.name)}
end)
|> partially_alphabetically_sort([], @last_categories)
end
defp partially_alphabetically_sort(keyed_list, first, last) do
{first_items, rest} =
Enum.split_with(keyed_list, fn {key, _} ->
key in first
end)
{last_items, rest} =
Enum.split_with(rest, fn {key, _} ->
key in last
end)
first_items
|> Enum.sort_by(fn {key, _} ->
Enum.find_index(first, &(&1 == key))
end)
|> Enum.concat(Enum.sort_by(rest, &elem(&1, 0)))
|> Enum.concat(
Enum.sort_by(last_items, fn {key, _} ->
Enum.find_index(last, &(&1 == key))
end)
)
end
end