improvement: upgrade to 3.0

This commit is contained in:
Zach Daniel 2024-04-02 20:24:23 -04:00
parent 6a943f22d7
commit 2221ef824d
59 changed files with 381 additions and 548 deletions

View file

@ -24,34 +24,43 @@ import { LiveSocket } from "phoenix_live_view";
import topbar from "../vendor/topbar"; import topbar from "../vendor/topbar";
function setCookie(name, value) { function setCookie(name, value) {
document.cookie = name + "=" + value + ";path=/;" + "expires=Fri, 31 Dec 9999 23:59:59 GMT;"; document.cookie =
name + "=" + value + ";path=/;" + "expires=Fri, 31 Dec 9999 23:59:59 GMT;";
} }
function getCookie(name) { function getCookie(name) {
const cookie = document.cookie.split("; ").find((row) => row.startsWith(name + "=")) const cookie = document.cookie
.split("; ")
.find((row) => row.startsWith(name + "="));
if (cookie) { if (cookie) {
return cookie.split("=")[1] return cookie.split("=")[1];
} }
} }
function cookiesAreAllowed() { function cookiesAreAllowed() {
return getCookie("cookieconsent_status") === "allow" return getCookie("cookieconsent_status") === "allow";
} }
function get_platform() { function get_platform() {
// 2022 way of detecting. Note : this userAgentData feature is available only in secure contexts (HTTPS) // 2022 way of detecting. Note : this userAgentData feature is available only in secure contexts (HTTPS)
if (typeof navigator.userAgentData !== 'undefined' && navigator.userAgentData != null) { if (
typeof navigator.userAgentData !== "undefined" &&
navigator.userAgentData != null
) {
return navigator.userAgentData.platform; return navigator.userAgentData.platform;
} }
// Deprecated but still works for most of the browser // Deprecated but still works for most of the browser
if (typeof navigator.platform !== 'undefined') { if (typeof navigator.platform !== "undefined") {
if (typeof navigator.userAgent !== 'undefined' && /android/.test(navigator.userAgent.toLowerCase())) { if (
typeof navigator.userAgent !== "undefined" &&
/android/.test(navigator.userAgent.toLowerCase())
) {
// android device's navigator.platform is often set as 'linux', so let's use userAgent for them // android device's navigator.platform is often set as 'linux', so let's use userAgent for them
return 'android'; return "android";
} }
return navigator.platform; return navigator.platform;
} }
return 'unknown'; return "unknown";
} }
let platform = get_platform(); let platform = get_platform();
@ -110,13 +119,15 @@ let scrolled = false;
Hooks.RightNav = { Hooks.RightNav = {
mounted() { mounted() {
this.intersectionObserver = this.intersectionObserver = new IntersectionObserver(
new IntersectionObserver((entries) => (entries) => this.onScrollChange(entries),
this.onScrollChange(entries), { rootMargin: "-10% 0px -89% 0px" } { rootMargin: "-10% 0px -89% 0px" },
); );
this.observeElements() this.observeElements();
window.addEventListener("hashchange", (event) => { this.handleHashChange(); }); window.addEventListener("hashchange", (event) => {
this.handleHashChange();
});
}, },
updated() { updated() {
this.intersectionObserver.disconnect(); this.intersectionObserver.disconnect();
@ -129,7 +140,9 @@ Hooks.RightNav = {
}, },
onScrollChange(entries) { onScrollChange(entries) {
// Wait for scrolling from initial page load to complete // Wait for scrolling from initial page load to complete
if (!scrolled) { return; } if (!scrolled) {
return;
}
for (entry of entries) { for (entry of entries) {
if (entry.isIntersecting) { if (entry.isIntersecting) {
@ -139,19 +152,21 @@ Hooks.RightNav = {
}, },
handleHashChange() { handleHashChange() {
if (window.location.hash) { if (window.location.hash) {
this.setAriaCurrent(window.location.hash.substring(1)) this.setAriaCurrent(window.location.hash.substring(1));
// Disable the insersection observer for 1s while the browser // Disable the insersection observer for 1s while the browser
// scrolls the selected element to the top. // scrolls the selected element to the top.
scrolled = false; scrolled = false;
setTimeout(() => { scrolled = true }, 1000); setTimeout(() => {
scrolled = true;
}, 1000);
} }
}, },
setAriaCurrent(id) { setAriaCurrent(id) {
const el = document.getElementById("right-nav-" + id); const el = document.getElementById("right-nav-" + id);
if (el) { if (el) {
for (elem of document.querySelectorAll('#right-nav a[aria-current]')) { for (elem of document.querySelectorAll("#right-nav a[aria-current]")) {
elem.removeAttribute('aria-current'); elem.removeAttribute("aria-current");
} }
el.setAttribute("aria-current", "true"); el.setAttribute("aria-current", "true");
} }
@ -201,9 +216,9 @@ window.addEventListener("phx:page-loading-start", ({ detail }) => {
scrolled = false; scrolled = false;
// close mobile sidebar on navigation // close mobile sidebar on navigation
mobileSideBar = document.getElementById("mobile-sidebar-hide") mobileSideBar = document.getElementById("mobile-sidebar-hide");
if (mobileSideBar) { if (mobileSideBar) {
mobileSideBar.click() mobileSideBar.click();
} }
if (!topBarScheduled) { if (!topBarScheduled) {
@ -219,13 +234,17 @@ window.addEventListener("phx:page-loading-stop", ({ detail }) => {
if (detail.kind === "initial" && window.location.hash) { if (detail.kind === "initial" && window.location.hash) {
scrollEl = document.getElementById(window.location.hash.substring(1)); scrollEl = document.getElementById(window.location.hash.substring(1));
} else if (detail.kind == "patch" && !window.location.hash) { } else if (detail.kind == "patch" && !window.location.hash) {
scrollEl = document.querySelector("#docs-window .nav-anchor") || document.querySelector("#docs-window h1"); scrollEl =
document.querySelector("#docs-window .nav-anchor") ||
document.querySelector("#docs-window h1");
} }
if (scrollEl) { if (scrollEl) {
Hooks.RightNav.setAriaCurrent(scrollEl.id); Hooks.RightNav.setAriaCurrent(scrollEl.id);
// Not using scroll polyfill here - doesn't respect scroll-padding-top CSS // Not using scroll polyfill here - doesn't respect scroll-padding-top CSS
scrollEl.scrollIntoView({ block: 'start' }) scrollEl.scrollIntoView({ block: "start" });
setTimeout(() => { scrolled = true; }, 1000); setTimeout(() => {
scrolled = true;
}, 1000);
} else { } else {
scrolled = true; scrolled = true;
} }
@ -243,13 +262,6 @@ window.addEventListener("phx:js:scroll-to", (e) => {
}); });
}); });
window.addEventListener("phx:selected-types", (e) => {
if (cookiesAreAllowed()) {
const cookie = e.detail.types.join(",");
setCookies("selected_types", cookie)
}
});
window.addEventListener("keydown", (event) => { window.addEventListener("keydown", (event) => {
if ((event.metaKey || event.ctrlKey) && event.key === "k") { if ((event.metaKey || event.ctrlKey) && event.key === "k") {
document.getElementById("search-button").click(); document.getElementById("search-button").click();
@ -258,9 +270,11 @@ window.addEventListener("keydown", (event) => {
}); });
window.addEventListener("keydown", (event) => { window.addEventListener("keydown", (event) => {
if (event.key === "Escape") { if (event.key === "Escape") {
const closeSearchVersions = document.getElementById("close-search-versions"); const closeSearchVersions = document.getElementById(
"close-search-versions",
);
if (closeSearchVersions && closeSearchVersions.offsetParent !== null) { if (closeSearchVersions && closeSearchVersions.offsetParent !== null) {
closeSearchVersions.click() closeSearchVersions.click();
} else { } else {
document.getElementById("close-search").click(); document.getElementById("close-search").click();
} }
@ -288,7 +302,7 @@ liveSocket.connect();
// >> liveSocket.disableLatencySim() // >> liveSocket.disableLatencySim()
window.liveSocket = liveSocket; window.liveSocket = liveSocket;
window.addEventListener("load", function() { window.addEventListener("load", function () {
window.cookieconsent.initialise({ window.cookieconsent.initialise({
content: { content: {
message: message:

View file

@ -25,7 +25,7 @@ config :ash_appsignal,
config :appsignal, :config, revision: "test-4" config :appsignal, :config, revision: "test-4"
config :ash_hq, config :ash_hq,
ash_apis: [ ash_domains: [
AshHq.Accounts, AshHq.Accounts,
AshHq.Blog, AshHq.Blog,
AshHq.Docs, AshHq.Docs,
@ -40,7 +40,6 @@ config :ash_hq, AshHq.Repo,
config :spark, :formatter, config :spark, :formatter,
remove_parens?: true, remove_parens?: true,
"Ash.Registry": [],
"Ash.Resource": [ "Ash.Resource": [
type: Ash.Resource, type: Ash.Resource,
section_order: [ section_order: [

View file

@ -2,13 +2,10 @@ defmodule AshHq.Accounts do
@moduledoc """ @moduledoc """
Handles user and user token related operations/state Handles user and user token related operations/state
""" """
use Ash.Api, otp_app: :ash_hq use Ash.Domain, otp_app: :ash_hq
authorization do
authorize :by_default
end
resources do resources do
registry AshHq.Accounts.Registry resource AshHq.Accounts.User
resource AshHq.Accounts.UserToken
end end
end end

View file

@ -1,11 +0,0 @@
defmodule AshHq.Accounts.Registry do
@moduledoc false
use Ash.Registry,
extensions: [Ash.Registry.ResourceValidations]
entries do
entry AshHq.Accounts.User
entry AshHq.Accounts.UserToken
end
end

View file

@ -1,26 +0,0 @@
defmodule AshHq.Accounts.User.Changes.RemoveAllTokens do
@moduledoc """
Removes all tokens for a given user.
Since Ash does not yet support bulk actions, this goes straight to the data layer.
"""
use Ash.Resource.Change
require Ash.Query
def change(changeset, _opts, _context) do
Ash.Changeset.after_action(
changeset,
fn _changeset, user ->
{:ok, query} =
AshHq.Accounts.UserToken
|> Ash.Query.filter(user_id == ^user.id)
|> Ash.Query.data_layer_query()
AshHq.Repo.delete_all(query)
{:ok, user}
end,
prepend?: true
)
end
end

View file

@ -6,25 +6,5 @@ defmodule AshHq.Accounts.User.Policies do
policy action(:read) do policy action(:read) do
authorize_if(expr(id == ^actor(:id))) authorize_if(expr(id == ^actor(:id)))
end end
policy action(:update_email) do
description("A logged in user can update their email")
authorize_if(expr(id == ^actor(:id)))
end
policy action(:resend_confirmation_instructions) do
description("A logged in user can request an email confirmation")
authorize_if(expr(id == ^actor(:id)))
end
policy action(:change_password) do
description("A logged in user can reset their password")
authorize_if(expr(id == ^actor(:id)))
end
policy action(:update_merch_settings) do
description("A logged in user can update their merch settings")
authorize_if(expr(id == ^actor(:id)))
end
end end
end end

View file

@ -2,6 +2,7 @@ defmodule AshHq.Accounts.User do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Accounts,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
fragments: [AshHq.Accounts.User.Policies] fragments: [AshHq.Accounts.User.Policies]
@ -11,130 +12,6 @@ defmodule AshHq.Accounts.User do
actions do actions do
defaults [:read] defaults [:read]
# create :register_with_github do
# argument :user_info, :map do
# allow_nil? false
# end
# argument :oauth_tokens, :map do
# allow_nil? false
# end
# change fn changeset, _ ->
# user_info = Ash.Changeset.get_argument(changeset, :user_info)
# changeset =
# if user_info["email_verified"] do
# Ash.Changeset.force_change_attribute(
# changeset,
# :confirmed_at,
# Ash.Changeset.get_attribute(changeset, :confirmed_at) || DateTime.utc_now()
# )
# else
# changeset
# end
# changeset
# |> Ash.Changeset.change_attribute(:email, Map.get(user_info, "email"))
# |> Ash.Changeset.change_attribute(:github_info, user_info)
# end
# change AshAuthentication.GenerateTokenChange
# upsert? true
# upsert_identity :unique_email
# end
# update :change_password do
# accept []
# argument :current_password, :string do
# sensitive? true
# allow_nil? false
# end
# argument :password, :string do
# sensitive? true
# allow_nil? false
# end
# argument :password_confirmation, :string do
# sensitive? true
# allow_nil? false
# end
# change set_context(%{strategy_name: :password})
# validate confirm(:password, :password_confirmation)
# validate {AshAuthentication.Strategy.Password.PasswordValidation,
# strategy_name: :password, password_argument: :current_password} do
# only_when_valid? true
# before_action? true
# end
# change AshAuthentication.Strategy.Password.HashPasswordChange
# end
# update :update_email do
# accept [:email]
# argument :current_password, :string do
# sensitive? true
# allow_nil? false
# end
# change set_context(%{strategy_name: :password})
# validate {AshAuthentication.Strategy.Password.PasswordValidation,
# password_argument: :current_password} do
# only_when_valid? true
# before_action? true
# end
# end
# update :resend_confirmation_instructions do
# accept []
# change fn changeset, _context ->
# Ash.Changeset.before_action(changeset, fn changeset ->
# case AshHq.Accounts.UserToken.email_token_for_user(changeset.data.id,
# authorize?: false
# ) do
# {:ok, %{extra_data: %{"email" => changing_to}}} ->
# temp_changeset = %{
# changeset
# | attributes: Map.put(changeset.attributes, :email, changing_to)
# }
# strategy = AshAuthentication.Info.strategy!(changeset.resource, :confirm)
# {:ok, token} =
# AshAuthentication.AddOn.Confirmation.confirmation_token(
# strategy,
# temp_changeset,
# changeset.data
# )
# AshHq.Accounts.User.Senders.SendConfirmationEmail.send(changeset.data, token, [])
# changeset
# _ ->
# Ash.Changeset.add_error(changeset, "Could not determine what email to use")
# end
# end)
# end
# end
# update :update_merch_settings do
# argument :address, :string
# argument :name, :string
# accept [:shirt_size]
# change set_attribute(:encrypted_address, arg(:address))
# change set_attribute(:encrypted_name, arg(:name))
# end
end end
attributes do attributes do
@ -146,7 +23,7 @@ defmodule AshHq.Accounts.User do
max_length: 160 max_length: 160
] ]
attribute :hashed_password, :string, private?: true, sensitive?: true attribute :hashed_password, :string, sensitive?: true
attribute :encrypted_name, :string attribute :encrypted_name, :string
attribute :encrypted_address, :string attribute :encrypted_address, :string
@ -160,7 +37,6 @@ defmodule AshHq.Accounts.User do
relationships do relationships do
has_one :token, AshHq.Accounts.UserToken do has_one :token, AshHq.Accounts.UserToken do
destination_attribute :user_id destination_attribute :user_id
private? true
end end
end end
@ -169,12 +45,6 @@ defmodule AshHq.Accounts.User do
repo AshHq.Repo repo AshHq.Repo
end end
code_interface do
define_for AshHq.Accounts
define :resend_confirmation_instructions
define :register_with_password, args: [:email, :password, :password_confirmation]
end
resource do resource do
description """ description """
Represents the user of a system. Represents the user of a system.
@ -188,9 +58,6 @@ defmodule AshHq.Accounts.User do
end end
changes do changes do
change AshHq.Accounts.User.Changes.RemoveAllTokens,
where: [action_is(:password_reset_with_password)]
change {AshHq.Changes.Encrypt, fields: [:encrypted_address, :encrypted_name]} change {AshHq.Changes.Encrypt, fields: [:encrypted_address, :encrypted_name]}
end end

View file

@ -2,27 +2,16 @@ defmodule AshHq.Accounts.UserToken do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Accounts,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
authorizers: [Ash.Policy.Authorizer] authorizers: [Ash.Policy.Authorizer]
actions do actions do
defaults [:read, :destroy] defaults [:read]
read :email_token_for_user do
get? true
argument :user_id, :uuid do
allow_nil? false
end
prepare build(sort: [updated_at: :desc], limit: 1)
filter expr(purpose == "confirm" and not is_nil(extra_data[:email]))
end
end end
token do attributes do
api AshHq.Accounts uuid_primary_key :id
end end
relationships do relationships do
@ -32,8 +21,7 @@ defmodule AshHq.Accounts.UserToken do
policies do policies do
policy always() do policy always() do
description """ description """
There are currently no usages of user tokens resource that should be publicly There are currently no usages of user tokens resource that should be publicly accessible.
accessible, they should all be using authorize?: false.
""" """
forbid_if always() forbid_if always()
@ -49,30 +37,9 @@ defmodule AshHq.Accounts.UserToken do
end end
end end
code_interface do
define_for AshHq.Accounts
define :destroy
define :email_token_for_user, args: [:user_id]
end
resource do resource do
description """ description """
Represents a token allowing a user to log in, reset their password, or confirm their email. Represents a token allowing a user to log in, reset their password, or confirm their email.
""" """
end end
changes do
change fn changeset, _ ->
case changeset.context[:ash_authentication][:user] do
nil ->
changeset
user ->
Ash.Changeset.manage_relationship(changeset, :user, user,
type: :append_and_remove
)
end
end,
on: [:create]
end
end end

View file

@ -1,52 +0,0 @@
defmodule AshHq.ApiHelpers do
@moduledoc false
defmacro __using__(_) do
quote do
def stream(query, opts \\ []) do
api = __MODULE__
query = Ash.Query.to_query(query)
query =
if query.action do
query
else
Ash.Query.for_read(
query,
Ash.Resource.Info.primary_action!(query.resource, :read).name
)
end
Stream.resource(
fn -> nil end,
fn
false ->
{:halt, nil}
after_keyset ->
if is_nil(query.action.pagination) || !query.action.pagination.keyset? do
raise "Keyset pagination must be enabled"
end
keyset = if after_keyset != nil, do: [after: after_keyset], else: []
page_opts = Keyword.merge([limit: 100], keyset)
opts =
[
page: page_opts
]
|> Keyword.merge(opts)
case api.read!(query, opts) do
%{more?: true, results: results} ->
{results, List.last(results).__metadata__.keyset}
%{results: results} ->
{results, false}
end
end,
& &1
)
end
end
end
end

View file

@ -7,6 +7,7 @@ defmodule AshHq.Application do
@impl true @impl true
def start(_type, _args) do def start(_type, _args) do
:erlang.system_flag(:backtrace_depth, 1000)
Appsignal.Phoenix.LiveView.attach() Appsignal.Phoenix.LiveView.attach()
# topologies = Application.get_env(:libcluster, :topologies) || [] # topologies = Application.get_env(:libcluster, :topologies) || []
@ -48,8 +49,8 @@ defmodule AshHq.Application do
end end
defp oban_worker do defp oban_worker do
apis = Application.fetch_env!(:ash_hq, :ash_apis) domains = Application.fetch_env!(:ash_hq, :ash_domains)
config = Application.fetch_env!(:ash_hq, Oban) config = Application.fetch_env!(:ash_hq, Oban)
{Oban, AshOban.config(apis, config)} {Oban, AshOban.config(domains, config)}
end end
end end

View file

@ -1,7 +1,7 @@
defmodule AshHq.Blog do defmodule AshHq.Blog do
@moduledoc "An api for interacting with the blog" @moduledoc "A domain for interacting with the blog"
use Ash.Api, use Ash.Domain,
extensions: [AshAdmin.Api] extensions: [AshAdmin.Domain]
admin do admin do
show? true show? true
@ -9,6 +9,7 @@ defmodule AshHq.Blog do
end end
resources do resources do
registry AshHq.Blog.Registry resource AshHq.Blog.Post
resource AshHq.Blog.Tag
end end
end end

View file

@ -1,10 +0,0 @@
defmodule AshHq.Blog.Registry do
@moduledoc "The resources used in the blog"
use Ash.Registry,
extensions: [Ash.Registry.ResourceValidations]
entries do
entry AshHq.Blog.Post
entry AshHq.Blog.Tag
end
end

View file

@ -1,6 +1,7 @@
defmodule AshHq.Blog.Post do defmodule AshHq.Blog.Post do
@moduledoc "A blog post. Uses the AshBlog data layer and therefore is static" @moduledoc "A blog post. Uses the AshBlog data layer and therefore is static"
use Ash.Resource, use Ash.Resource,
domain: AshHq.Blog,
otp_app: :ash_hq, otp_app: :ash_hq,
data_layer: AshBlog.DataLayer, data_layer: AshBlog.DataLayer,
extensions: [AshHq.Docs.Extensions.RenderMarkdown, AshAdmin.Resource] extensions: [AshHq.Docs.Extensions.RenderMarkdown, AshAdmin.Resource]
@ -22,6 +23,7 @@ defmodule AshHq.Blog.Post do
end end
actions do actions do
default_accept :*
defaults [:create, :read, :update] defaults [:create, :read, :update]
read :published do read :published do
@ -52,11 +54,13 @@ defmodule AshHq.Blog.Post do
uuid_primary_key :id uuid_primary_key :id
attribute :tag_line, :string do attribute :tag_line, :string do
public? true
allow_nil? false allow_nil? false
constraints max_length: 250 constraints max_length: 250
end end
attribute :tag_names, {:array, :ci_string} do attribute :tag_names, {:array, :ci_string} do
public? true
constraints items: [ constraints items: [
match: ~r/^[a-zA-Z]*$/, match: ~r/^[a-zA-Z]*$/,
casing: :lower casing: :lower
@ -64,10 +68,12 @@ defmodule AshHq.Blog.Post do
end end
attribute :author, :string do attribute :author, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :body_html, :string do attribute :body_html, :string do
public? true
writable? false writable? false
end end
@ -76,6 +82,7 @@ defmodule AshHq.Blog.Post do
relationships do relationships do
has_many :tags, AshHq.Blog.Tag do has_many :tags, AshHq.Blog.Tag do
public? true
manual fn posts, %{query: query} -> manual fn posts, %{query: query} ->
all_tags = Enum.flat_map(posts, &(&1.tag_names || [])) all_tags = Enum.flat_map(posts, &(&1.tag_names || []))
@ -83,7 +90,7 @@ defmodule AshHq.Blog.Post do
query query
|> Ash.Query.unset([:limit, :offset]) |> Ash.Query.unset([:limit, :offset])
|> Ash.Query.filter(name in ^all_tags) |> Ash.Query.filter(name in ^all_tags)
|> AshHq.Blog.read!() |> Ash.read!()
{:ok, {:ok,
Map.new(posts, fn post -> Map.new(posts, fn post ->
@ -94,7 +101,6 @@ defmodule AshHq.Blog.Post do
end end
code_interface do code_interface do
define_for AshHq.Blog
define :published define :published
define :by_slug, args: [:slug] define :by_slug, args: [:slug]
end end

View file

@ -1,6 +1,7 @@
defmodule AshHq.Blog.Tag do defmodule AshHq.Blog.Tag do
@moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static" @moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static"
use Ash.Resource, use Ash.Resource,
domain: AshHq.Blog,
data_layer: AshCsv.DataLayer data_layer: AshCsv.DataLayer
csv do csv do
@ -11,6 +12,7 @@ defmodule AshHq.Blog.Tag do
end end
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
create :upsert do create :upsert do
@ -21,6 +23,7 @@ defmodule AshHq.Blog.Tag do
attributes do attributes do
attribute :name, :ci_string do attribute :name, :ci_string do
public? true
allow_nil? false allow_nil? false
primary_key? true primary_key? true
constraints casing: :lower constraints casing: :lower
@ -28,7 +31,6 @@ defmodule AshHq.Blog.Tag do
end end
code_interface do code_interface do
define_for AshHq.Blog
define :upsert, args: [:name] define :upsert, args: [:name]
define :read define :read
define :destroy define :destroy

View file

@ -1,6 +1,6 @@
defmodule AshHq.Calculations.Decrypt do defmodule AshHq.Calculations.Decrypt do
@moduledoc "Decrypts a given value on demand" @moduledoc "Decrypts a given value on demand"
use Ash.Calculation use Ash.Resource.Calculation
def calculate(records, opts, _) do def calculate(records, opts, _) do
{:ok, {:ok,
@ -19,10 +19,6 @@ defmodule AshHq.Calculations.Decrypt do
end)} end)}
end end
def select(_, opts, _) do
[opts[:field]]
end
def load(_, opts, _) do def load(_, opts, _) do
[opts[:field]] [opts[:field]]
end end

View file

@ -1,6 +1,6 @@
defmodule AshHq.Discord do defmodule AshHq.Discord do
@moduledoc "Discord api import & interactions" @moduledoc "Discord api import & interactions"
use Ash.Api use Ash.Domain
resources do resources do
resource AshHq.Discord.Attachment resource AshHq.Discord.Attachment

View file

@ -1,24 +1,27 @@
defmodule AshHq.Discord.Attachment do defmodule AshHq.Discord.Attachment do
@moduledoc "A discord attachment on a message" @moduledoc "A discord attachment on a message"
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
end end
attributes do attributes do
integer_primary_key :id, generated?: false, writable?: true integer_primary_key :id, generated?: false, writable?: true
attribute :filename, :string attribute :filename, :string, public?: true
attribute :size, :integer attribute :size, :integer, public?: true
attribute :url, :string attribute :url, :string, public?: true
attribute :proxy_url, :string attribute :proxy_url, :string, public?: true
attribute :height, :integer attribute :height, :integer, public?: true
attribute :width, :integer attribute :width, :integer, public?: true
end end
relationships do relationships do
belongs_to :message, AshHq.Discord.Message do belongs_to :message, AshHq.Discord.Message do
public? true
allow_nil? false allow_nil? false
attribute_type :integer attribute_type :integer
end end

View file

@ -4,9 +4,11 @@ defmodule AshHq.Discord.Channel do
""" """
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
create :upsert do create :upsert do
@ -18,16 +20,20 @@ defmodule AshHq.Discord.Channel do
integer_primary_key :id, writable?: true, generated?: false integer_primary_key :id, writable?: true, generated?: false
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
end end
relationships do relationships do
has_many :threads, AshHq.Discord.Thread has_many :threads, AshHq.Discord.Thread do
public? true
end
end end
postgres do postgres do
@ -36,7 +42,6 @@ defmodule AshHq.Discord.Channel do
end end
code_interface do code_interface do
define_for AshHq.Discord
define :read define :read
define :upsert define :upsert
end end

View file

@ -3,6 +3,7 @@ defmodule AshHq.Discord.Message do
Discord messages synchronized by the discord bot Discord messages synchronized by the discord bot
""" """
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [ extensions: [
AshHq.Docs.Extensions.RenderMarkdown, AshHq.Docs.Extensions.RenderMarkdown,
@ -10,6 +11,8 @@ defmodule AshHq.Discord.Message do
] ]
actions do actions do
default_accept :*
defaults [:read, :destroy] defaults [:read, :destroy]
create :create do create :create do
@ -25,6 +28,7 @@ defmodule AshHq.Discord.Message do
end end
update :update do update :update do
require_atomic? false
primary? true primary? true
argument :attachments, {:array, :map} argument :attachments, {:array, :map}
argument :reactions, {:array, :map} argument :reactions, {:array, :map}
@ -59,25 +63,37 @@ defmodule AshHq.Discord.Message do
integer_primary_key :id, generated?: false, writable?: true integer_primary_key :id, generated?: false, writable?: true
attribute :author, :string do attribute :author, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :content, :string attribute :content, :string do
attribute :content_html, :string public? true
end
attribute :content_html, :string do
public? true
end
attribute :timestamp, :utc_datetime do attribute :timestamp, :utc_datetime do
public? true
allow_nil? false allow_nil? false
end end
end end
relationships do relationships do
belongs_to :thread, AshHq.Discord.Thread do belongs_to :thread, AshHq.Discord.Thread do
public? true
attribute_type :integer attribute_type :integer
allow_nil? false allow_nil? false
end end
has_many :attachments, AshHq.Discord.Attachment has_many :attachments, AshHq.Discord.Attachment do
has_many :reactions, AshHq.Discord.Reaction public? true
end
has_many :reactions, AshHq.Discord.Reaction do
public? true
end
end end
postgres do postgres do

View file

@ -3,9 +3,11 @@ defmodule AshHq.Discord.Reaction do
Reactions store emoji reaction counts. Reactions store emoji reaction counts.
""" """
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
end end
@ -13,16 +15,19 @@ defmodule AshHq.Discord.Reaction do
uuid_primary_key :id uuid_primary_key :id
attribute :count, :integer do attribute :count, :integer do
public? true
allow_nil? false allow_nil? false
end end
attribute :emoji, :string do attribute :emoji, :string do
public? true
allow_nil? false allow_nil? false
end end
end end
relationships do relationships do
belongs_to :message, AshHq.Discord.Message do belongs_to :message, AshHq.Discord.Message do
public? true
attribute_type :integer attribute_type :integer
allow_nil? false allow_nil? false
end end

View file

@ -1,9 +1,11 @@
defmodule AshHq.Discord.Tag do defmodule AshHq.Discord.Tag do
@moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static" @moduledoc "A tag that can be applied to a post. Currently uses CSV data layer and therefore is static"
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
create :upsert do create :upsert do
@ -16,14 +18,15 @@ defmodule AshHq.Discord.Tag do
integer_primary_key :id, generated?: false, writable?: true integer_primary_key :id, generated?: false, writable?: true
attribute :name, :ci_string do attribute :name, :ci_string do
public? true
allow_nil? false allow_nil? false
end end
end end
relationships do relationships do
belongs_to :channel, AshHq.Discord.Channel do belongs_to :channel, AshHq.Discord.Channel do
public? true
attribute_type :integer attribute_type :integer
attribute_writable? true
end end
end end
@ -33,7 +36,6 @@ defmodule AshHq.Discord.Tag do
end end
code_interface do code_interface do
define_for AshHq.Discord
define :upsert, args: [:channel_id, :id, :name] define :upsert, args: [:channel_id, :id, :name]
define :read define :read
define :destroy define :destroy

View file

@ -4,11 +4,13 @@ defmodule AshHq.Discord.Thread do
""" """
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
import Ecto.Query import Ecto.Query
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
read :feed do read :feed do
@ -64,31 +66,39 @@ defmodule AshHq.Discord.Thread do
attributes do attributes do
integer_primary_key :id, generated?: false, writable?: true integer_primary_key :id, generated?: false, writable?: true
attribute :type, :integer attribute :type, :integer do
public? true
end
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :author, :string do attribute :author, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :create_timestamp, :utc_datetime do attribute :create_timestamp, :utc_datetime do
public? true
allow_nil? false allow_nil? false
end end
end end
relationships do relationships do
has_many :messages, AshHq.Discord.Message has_many :messages, AshHq.Discord.Message do
public? true
end
belongs_to :channel, AshHq.Discord.Channel do belongs_to :channel, AshHq.Discord.Channel do
public? true
attribute_type :integer attribute_type :integer
allow_nil? false allow_nil? false
attribute_writable? true
end end
many_to_many :tags, AshHq.Discord.Tag do many_to_many :tags, AshHq.Discord.Tag do
public? true
through AshHq.Discord.ThreadTag through AshHq.Discord.ThreadTag
source_attribute_on_join_resource :thread_id source_attribute_on_join_resource :thread_id
destination_attribute_on_join_resource :tag_id destination_attribute_on_join_resource :tag_id
@ -101,7 +111,6 @@ defmodule AshHq.Discord.Thread do
end end
code_interface do code_interface do
define_for AshHq.Discord
define :upsert define :upsert
define :by_id, action: :read, get_by: [:id] define :by_id, action: :read, get_by: [:id]
define :feed, args: [:channel] define :feed, args: [:channel]

View file

@ -1,9 +1,11 @@
defmodule AshHq.Discord.ThreadTag do defmodule AshHq.Discord.ThreadTag do
@moduledoc "Joins a thread to a tag" @moduledoc "Joins a thread to a tag"
use Ash.Resource, use Ash.Resource,
domain: AshHq.Discord,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:read, :destroy] defaults [:read, :destroy]
create :tag do create :tag do
@ -13,16 +15,16 @@ defmodule AshHq.Discord.ThreadTag do
relationships do relationships do
belongs_to :thread, AshHq.Discord.Thread do belongs_to :thread, AshHq.Discord.Thread do
public? true
primary_key? true primary_key? true
allow_nil? false allow_nil? false
attribute_writable? true
attribute_type :integer attribute_type :integer
end end
belongs_to :tag, AshHq.Discord.Tag do belongs_to :tag, AshHq.Discord.Tag do
public? true
primary_key? true primary_key? true
allow_nil? false allow_nil? false
attribute_writable? true
attribute_type :integer attribute_type :integer
end end
end end
@ -33,7 +35,6 @@ defmodule AshHq.Discord.ThreadTag do
end end
code_interface do code_interface do
define_for AshHq.Discord
define :tag, args: [:thread_id, :tag_id] define :tag, args: [:thread_id, :tag_id]
end end
end end

View file

@ -2,14 +2,12 @@ defmodule AshHq.Docs do
@moduledoc """ @moduledoc """
Handles documentation data. Handles documentation data.
""" """
use Ash.Api, use Ash.Domain,
extensions: [ extensions: [
AshGraphql.Api, AshGraphql.Domain,
AshAdmin.Api AshAdmin.Domain
] ]
use AshHq.ApiHelpers
admin do admin do
show? true show? true
default_resource_page :primary_read default_resource_page :primary_read
@ -20,6 +18,14 @@ defmodule AshHq.Docs do
end end
resources do resources do
registry AshHq.Docs.Registry resource AshHq.Docs.Dsl
resource AshHq.Docs.Extension
resource AshHq.Docs.Function
resource AshHq.Docs.Guide
resource AshHq.Docs.Library
resource AshHq.Docs.LibraryVersion
resource AshHq.Docs.MixTask
resource AshHq.Docs.Module
resource AshHq.Docs.Option
end end
end end

View file

@ -30,7 +30,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
Ash.Changeset.get_attribute(changeset, :name) Ash.Changeset.get_attribute(changeset, :name)
changeset.resource == AshHq.Docs.Function -> changeset.resource == AshHq.Docs.Function ->
AshHq.Docs.get!( Ash.get!(
AshHq.Docs.Module, AshHq.Docs.Module,
Ash.Changeset.get_attribute(changeset, :module_id) Ash.Changeset.get_attribute(changeset, :module_id)
).name ).name
@ -49,7 +49,7 @@ defmodule AshHq.Docs.Extensions.RenderMarkdown.Changes.RenderMarkdown do
AshHq.Docs.Library AshHq.Docs.Library
|> Ash.Query.select(:name) |> Ash.Query.select(:name)
|> Ash.Query.filter(versions.id == ^library_version_id) |> Ash.Query.filter(versions.id == ^library_version_id)
|> AshHq.Docs.read_one!() |> Ash.read_one!()
|> Map.get(:name) |> Map.get(:name)
end end

View file

@ -45,7 +45,6 @@ defmodule AshHq.Docs.Extensions.Search.Transformers.AddSearchStructure do
Ash.Resource.Dsl, Ash.Resource.Dsl,
[:attributes], [:attributes],
:attribute, :attribute,
private?: true,
name: config.sanitized_name_attribute, name: config.sanitized_name_attribute,
type: :string, type: :string,
allow_nil?: false allow_nil?: false

View file

@ -3,8 +3,8 @@ defmodule AshHq.Docs.Extensions.Search.Types do
A static list of all search types that currently exist A static list of all search types that currently exist
""" """
@search_types [AshHq.Docs.Registry] @search_types [AshHq.Docs]
|> Enum.flat_map(&Ash.Registry.Info.entries/1) |> Enum.flat_map(&Ash.Domain.Info.resources/1)
|> Enum.filter(&(AshHq.Docs.Extensions.Search in Spark.extensions(&1))) |> Enum.filter(&(AshHq.Docs.Extensions.Search in Spark.extensions(&1)))
|> Enum.map(&AshHq.Docs.Extensions.Search.type/1) |> Enum.map(&AshHq.Docs.Extensions.Search.type/1)
|> Enum.uniq() |> Enum.uniq()

View file

@ -73,7 +73,7 @@ defmodule AshHq.Docs.Indexer do
resource resource
|> Ash.Query.filter(id in ^ids) |> Ash.Query.filter(id in ^ids)
|> Ash.Query.load(AshHq.Docs.Extensions.Search.load_for_search(resource)) |> Ash.Query.load(AshHq.Docs.Extensions.Search.load_for_search(resource))
|> AshHq.Docs.read!() |> Ash.read!()
|> Enum.map(fn item -> |> Enum.map(fn item ->
Ash.Resource.put_metadata(item, :search_score, scores[item.id]) Ash.Resource.put_metadata(item, :search_score, scores[item.id])
end) end)
@ -125,7 +125,7 @@ defmodule AshHq.Docs.Indexer do
defp dsls do defp dsls do
AshHq.Docs.Dsl AshHq.Docs.Dsl
|> Ash.Query.load([:library_name, :extension_module]) |> Ash.Query.load([:library_name, :extension_module])
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn dsl -> |> Stream.map(fn dsl ->
%{ %{
"id" => id("dsl", dsl.id), "id" => id("dsl", dsl.id),
@ -140,7 +140,7 @@ defmodule AshHq.Docs.Indexer do
defp guides do defp guides do
AshHq.Docs.Guide AshHq.Docs.Guide
|> Ash.Query.load(library_version: :library) |> Ash.Query.load(library_version: :library)
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn guide -> |> Stream.map(fn guide ->
%{ %{
"id" => id("guide", guide.id), "id" => id("guide", guide.id),
@ -154,7 +154,7 @@ defmodule AshHq.Docs.Indexer do
defp options do defp options do
AshHq.Docs.Option AshHq.Docs.Option
|> Ash.Query.load([:library_name, :extension_module]) |> Ash.Query.load([:library_name, :extension_module])
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn option -> |> Stream.map(fn option ->
%{ %{
"id" => id("option", option.id), "id" => id("option", option.id),
@ -169,7 +169,7 @@ defmodule AshHq.Docs.Indexer do
defp modules do defp modules do
AshHq.Docs.Module AshHq.Docs.Module
|> Ash.Query.load([:library_name]) |> Ash.Query.load([:library_name])
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn module -> |> Stream.map(fn module ->
%{ %{
"id" => id("module", module.id), "id" => id("module", module.id),
@ -184,7 +184,7 @@ defmodule AshHq.Docs.Indexer do
defp mix_tasks do defp mix_tasks do
AshHq.Docs.MixTask AshHq.Docs.MixTask
|> Ash.Query.load([:library_name]) |> Ash.Query.load([:library_name])
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn mix_task -> |> Stream.map(fn mix_task ->
%{ %{
"id" => id("mix_task", mix_task.id), "id" => id("mix_task", mix_task.id),
@ -199,7 +199,7 @@ defmodule AshHq.Docs.Indexer do
defp functions do defp functions do
AshHq.Docs.Function AshHq.Docs.Function
|> Ash.Query.load([:library_name, :call_name]) |> Ash.Query.load([:library_name, :call_name])
|> AshHq.Docs.stream!() |> Ash.stream!()
|> Stream.map(fn function -> |> Stream.map(fn function ->
%{ %{
"id" => id("function", function.id), "id" => id("function", function.id),

View file

@ -1,17 +0,0 @@
defmodule AshHq.Docs.Registry do
@moduledoc false
use Ash.Registry,
extensions: [Ash.Registry.ResourceValidations]
entries do
entry AshHq.Docs.Dsl
entry AshHq.Docs.Extension
entry AshHq.Docs.Function
entry AshHq.Docs.Guide
entry AshHq.Docs.Library
entry AshHq.Docs.LibraryVersion
entry AshHq.Docs.MixTask
entry AshHq.Docs.Module
entry AshHq.Docs.Option
end
end

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.Dsl do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -57,39 +59,61 @@ defmodule AshHq.Docs.Dsl do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :requires_extension, :string attribute :requires_extension, :string do
public? true
end
attribute :doc, :string do attribute :doc, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :doc_html, :string do attribute :doc_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :imports, {:array, :string} do attribute :imports, {:array, :string} do
public? true
default [] default []
end end
attribute :examples, {:array, :string} attribute :examples, {:array, :string} do
attribute :args, {:array, :string} public? true
end
attribute :args, {:array, :string} do
public? true
end
attribute :optional_args, {:array, :string} do attribute :optional_args, {:array, :string} do
public? true
default [] default []
end end
attribute :arg_defaults, :map attribute :arg_defaults, :map do
attribute :path, {:array, :string} public? true
attribute :recursive_as, :string end
attribute :order, :integer, allow_nil?: false attribute :path, {:array, :string} do
public? true
end
attribute :recursive_as, :string do
public? true
end
attribute :order, :integer do
public? true
allow_nil? false
end
attribute :type, :atom do attribute :type, :atom do
public? true
allow_nil? false allow_nil? false
constraints one_of: [:entity, :section] constraints one_of: [:entity, :section]
end end
@ -99,16 +123,24 @@ defmodule AshHq.Docs.Dsl do
relationships do relationships do
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
belongs_to :extension, AshHq.Docs.Extension do belongs_to :extension, AshHq.Docs.Extension do
public? true
allow_nil? true allow_nil? true
end end
belongs_to :dsl, __MODULE__ belongs_to :dsl, __MODULE__ do
has_many :options, AshHq.Docs.Option public? true
has_many :dsls, __MODULE__ end
has_many :options, AshHq.Docs.Option do
public? true
end
has_many :dsls, __MODULE__ do
public? true
end
end end
postgres do postgres do
@ -124,7 +156,6 @@ defmodule AshHq.Docs.Dsl do
end end
code_interface do code_interface do
define_for AshHq.Docs
define :read define :read
end end

View file

@ -2,9 +2,11 @@ defmodule AshHq.Docs.Extension do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -33,18 +35,25 @@ defmodule AshHq.Docs.Extension do
attributes do attributes do
uuid_primary_key :id uuid_primary_key :id
attribute :module, :string attribute :module, :string do
public? true
end
timestamps() timestamps()
end end
relationships do relationships do
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
has_many :dsls, AshHq.Docs.Dsl has_many :dsls, AshHq.Docs.Dsl do
has_many :options, AshHq.Docs.Option public? true
end
has_many :options, AshHq.Docs.Option do
public? true
end
end end
postgres do postgres do
@ -57,7 +66,6 @@ defmodule AshHq.Docs.Extension do
end end
code_interface do code_interface do
define_for AshHq.Docs
define :destroy define :destroy
end end

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.Function do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -51,45 +53,58 @@ defmodule AshHq.Docs.Function do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :file, :string attribute :file, :string do
attribute :line, :integer public? true
end
attribute :line, :integer do
public? true
end
attribute :arity, :integer do attribute :arity, :integer do
public? true
allow_nil? false allow_nil? false
end end
attribute :type, :atom do attribute :type, :atom do
public? true
constraints one_of: [:function, :macro, :callback, :type] constraints one_of: [:function, :macro, :callback, :type]
allow_nil? false allow_nil? false
end end
attribute :heads, {:array, :string} do attribute :heads, {:array, :string} do
public? true
default [] default []
end end
attribute :heads_html, {:array, :string} do attribute :heads_html, {:array, :string} do
public? true
default [] default []
end end
attribute :doc, :string do attribute :doc, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :doc_html, :string do attribute :doc_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
attribute :deprecated, :string do attribute :deprecated, :string do
public? true
allow_nil? true allow_nil? true
end end
@ -98,10 +113,12 @@ defmodule AshHq.Docs.Function do
relationships do relationships do
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
belongs_to :module, AshHq.Docs.Module do belongs_to :module, AshHq.Docs.Module do
public? true
allow_nil? true allow_nil? true
end end
end end
@ -115,9 +132,6 @@ defmodule AshHq.Docs.Function do
end end
end end
code_interface do
define_for AshHq.Docs
end
resource do resource do
description "A function in a module exposed by an Ash library" description "A function in a module exposed by an Ash library"

View file

@ -1,6 +1,7 @@
defmodule AshHq.Docs.Guide do defmodule AshHq.Docs.Guide do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [ extensions: [
AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.Search,
@ -10,6 +11,7 @@ defmodule AshHq.Docs.Guide do
] ]
actions do actions do
default_accept :*
defaults [:create, :update, :destroy] defaults [:create, :update, :destroy]
read :read do read :read do
@ -66,39 +68,47 @@ defmodule AshHq.Docs.Guide do
uuid_primary_key :id uuid_primary_key :id
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :text, :string do attribute :text, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :text_html, :string do attribute :text_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :category, :string do attribute :category, :string do
public? true
default "Topics" default "Topics"
allow_nil? false allow_nil? false
end end
attribute :route, :string do attribute :route, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :sanitized_route, :string do attribute :sanitized_route, :string do
public? true
allow_nil? false allow_nil? false
writable? false writable? false
end end
attribute :default, :boolean do attribute :default, :boolean do
public? true
default false default false
allow_nil? false allow_nil? false
end end
@ -121,9 +131,6 @@ defmodule AshHq.Docs.Guide do
end end
end end
code_interface do
define_for AshHq.Docs
end
resource do resource do
description "Represents a markdown guide exposed by a library" description "Represents a markdown guide exposed by a library"

View file

@ -75,7 +75,7 @@ defmodule AshHq.Docs.Library.Actions.Import do
Logger.info("Starting import of #{name}: #{version}") Logger.info("Starting import of #{name}: #{version}")
if AshHq.Docs.exists?( if Ash.exists?(
Ash.Query.for_read(AshHq.Docs.LibraryVersion, :read) Ash.Query.for_read(AshHq.Docs.LibraryVersion, :read)
|> Ash.Query.filter(library_id == ^library.id and version == ^version) |> Ash.Query.filter(library_id == ^library.id and version == ^version)
) do ) do

View file

@ -1,10 +1,12 @@
defmodule AshHq.Docs.Library do defmodule AshHq.Docs.Library do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshOban] extensions: [AshOban]
actions do actions do
default_accept :*
defaults [:create, :update, :destroy] defaults [:create, :update, :destroy]
read :read do read :read do
@ -31,6 +33,7 @@ defmodule AshHq.Docs.Library do
end end
update :import do update :import do
require_atomic? false
transaction? false transaction? false
argument :metadata, :map do argument :metadata, :map do
@ -49,7 +52,7 @@ defmodule AshHq.Docs.Library do
end end
oban do oban do
api AshHq.Docs domain AshHq.Docs
triggers do triggers do
trigger :import do trigger :import do
@ -69,32 +72,42 @@ defmodule AshHq.Docs.Library do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :display_name, :string do attribute :display_name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
attribute :description, :string attribute :description, :string do
public? true
end
attribute :repo_org, :string do attribute :repo_org, :string do
public? true
allow_nil? false allow_nil? false
default "ash-project" default "ash-project"
end end
attribute :module_prefixes, {:array, :string} do attribute :module_prefixes, {:array, :string} do
public? true
allow_nil? false allow_nil? false
default [] default []
end end
attribute :mix_project, :string attribute :mix_project, :string do
public? true
end
attribute :skip_versions, {:array, :string} do attribute :skip_versions, {:array, :string} do
public? true
default [] default []
allow_nil? false allow_nil? false
end end
@ -103,9 +116,12 @@ defmodule AshHq.Docs.Library do
end end
relationships do relationships do
has_many :versions, AshHq.Docs.LibraryVersion has_many :versions, AshHq.Docs.LibraryVersion do
public? true
end
has_one :latest_library_version, AshHq.Docs.LibraryVersion do has_one :latest_library_version, AshHq.Docs.LibraryVersion do
public? true
sort version: :desc sort version: :desc
from_many? true from_many? true
end end
@ -119,8 +135,6 @@ defmodule AshHq.Docs.Library do
end end
code_interface do code_interface do
define_for AshHq.Docs
define :read define :read
define :by_name, args: [:name], get?: true define :by_name, args: [:name], get?: true
define :create define :create

View file

@ -5,10 +5,10 @@ defmodule AshHq.Docs.Library.Preparations.FilterPendingImport do
query query
|> Ash.Query.ensure_selected([:name]) |> Ash.Query.ensure_selected([:name])
|> Ash.Query.load(:latest_version) |> Ash.Query.load(:latest_version)
|> Ash.Query.after_action(fn query, results -> |> Ash.Query.after_action(fn _query, results ->
pending_import = pending_import =
results results
|> query.api.load!(:latest_version) |> Ash.load!(:latest_version)
|> Enum.flat_map(fn result -> |> Enum.flat_map(fn result ->
hex_info = hex_info =
Finch.build(:get, "https://hex.pm/api/packages/#{result.name}") Finch.build(:get, "https://hex.pm/api/packages/#{result.name}")

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.LibraryVersion do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -90,10 +92,12 @@ defmodule AshHq.Docs.LibraryVersion do
uuid_primary_key :id uuid_primary_key :id
attribute :version, :string do attribute :version, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :hydrated, :boolean do attribute :hydrated, :boolean do
public? true
default false default false
allow_nil? false allow_nil? false
end end
@ -103,13 +107,22 @@ defmodule AshHq.Docs.LibraryVersion do
relationships do relationships do
belongs_to :library, AshHq.Docs.Library do belongs_to :library, AshHq.Docs.Library do
public? true
allow_nil? true allow_nil? true
end end
has_many :extensions, AshHq.Docs.Extension has_many :extensions, AshHq.Docs.Extension do
has_many :guides, AshHq.Docs.Guide public? true
has_many :modules, AshHq.Docs.Module end
has_many :mix_tasks, AshHq.Docs.MixTask has_many :guides, AshHq.Docs.Guide do
public? true
end
has_many :modules, AshHq.Docs.Module do
public? true
end
has_many :mix_tasks, AshHq.Docs.MixTask do
public? true
end
end end
postgres do postgres do
@ -118,7 +131,6 @@ defmodule AshHq.Docs.LibraryVersion do
end end
code_interface do code_interface do
define_for AshHq.Docs
define :build, args: [:library, :version] define :build, args: [:library, :version]
define :defined_for, args: [:library, :versions] define :defined_for, args: [:library, :versions]
define :by_version, args: [:library, :version] define :by_version, args: [:library, :version]

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.MixTask do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -48,30 +50,39 @@ defmodule AshHq.Docs.MixTask do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :category, :string do attribute :category, :string do
public? true
allow_nil? false allow_nil? false
default "Misc" default "Misc"
end end
attribute :file, :string attribute :file, :string do
public? true
end
attribute :module_name, :string attribute :module_name, :string do
public? true
end
attribute :doc, :string do attribute :doc, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :doc_html, :string do attribute :doc_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
@ -80,6 +91,7 @@ defmodule AshHq.Docs.MixTask do
relationships do relationships do
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
end end
@ -93,9 +105,6 @@ defmodule AshHq.Docs.MixTask do
end end
end end
code_interface do
define_for AshHq.Docs
end
resource do resource do
description "Represents a mix task that has been exposed by a library" description "Represents a mix task that has been exposed by a library"

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.Module do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -51,28 +53,35 @@ defmodule AshHq.Docs.Module do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :category, :string do attribute :category, :string do
public? true
allow_nil? false allow_nil? false
default "Misc" default "Misc"
end end
attribute :file, :string attribute :file, :string do
public? true
end
attribute :doc, :string do attribute :doc, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :doc_html, :string do attribute :doc_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :order, :integer do attribute :order, :integer do
public? true
allow_nil? false allow_nil? false
end end
@ -81,10 +90,13 @@ defmodule AshHq.Docs.Module do
relationships do relationships do
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
has_many :functions, AshHq.Docs.Function has_many :functions, AshHq.Docs.Function do
public? true
end
end end
postgres do postgres do
@ -96,9 +108,6 @@ defmodule AshHq.Docs.Module do
end end
end end
code_interface do
define_for AshHq.Docs
end
resource do resource do
description "Represents a module that has been exposed by a library" description "Represents a module that has been exposed by a library"

View file

@ -2,10 +2,12 @@ defmodule AshHq.Docs.Option do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.Docs,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown] extensions: [AshHq.Docs.Extensions.Search, AshHq.Docs.Extensions.RenderMarkdown]
actions do actions do
default_accept :*
defaults [:update, :destroy] defaults [:update, :destroy]
read :read do read :read do
@ -53,52 +55,70 @@ defmodule AshHq.Docs.Option do
uuid_primary_key :id uuid_primary_key :id
attribute :name, :string do attribute :name, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :type, :string do attribute :type, :string do
public? true
allow_nil? false allow_nil? false
end end
attribute :doc, :string do attribute :doc, :string do
public? true
allow_nil? false allow_nil? false
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
default "" default ""
end end
attribute :doc_html, :string do attribute :doc_html, :string do
public? true
constraints trim?: false, allow_empty?: true constraints trim?: false, allow_empty?: true
writable? false writable? false
end end
attribute :required, :boolean do attribute :required, :boolean do
public? true
allow_nil? false allow_nil? false
default false default false
end end
attribute :argument_index, :integer attribute :argument_index, :integer do
public? true
end
attribute :links, :map do attribute :links, :map do
public? true
default %{} default %{}
end end
attribute :default, :string attribute :default, :string do
attribute :path, {:array, :string} public? true
attribute :order, :integer, allow_nil?: false end
attribute :path, {:array, :string} do
public? true
end
attribute :order, :integer do
public? true
allow_nil? false
end
timestamps() timestamps()
end end
relationships do relationships do
belongs_to :dsl, AshHq.Docs.Dsl do belongs_to :dsl, AshHq.Docs.Dsl do
public? true
allow_nil? true allow_nil? true
end end
belongs_to :library_version, AshHq.Docs.LibraryVersion do belongs_to :library_version, AshHq.Docs.LibraryVersion do
public? true
allow_nil? true allow_nil? true
end end
belongs_to :extension, AshHq.Docs.Extension do belongs_to :extension, AshHq.Docs.Extension do
public? true
allow_nil? true allow_nil? true
end end
end end
@ -114,7 +134,6 @@ defmodule AshHq.Docs.Option do
end end
code_interface do code_interface do
define_for AshHq.Docs
define :read define :read
end end

View file

@ -5,9 +5,8 @@ defmodule AshHq.Github.Contributor.Actions.Import do
def run(_input, _, _) do def run(_input, _, _) do
AshHq.Docs.Library AshHq.Docs.Library
|> AshHq.Docs.read!() |> Ash.stream!()
|> Stream.flat_map(fn library -> |> Stream.flat_map(fn library ->
:timer.sleep(1000)
opts = [] opts = []
opts = opts =
@ -33,7 +32,7 @@ defmodule AshHq.Github.Contributor.Actions.Import do
Map.put(contributor, "order", index) Map.put(contributor, "order", index)
end) end)
|> Stream.uniq_by(&Map.get(&1, "id")) |> Stream.uniq_by(&Map.get(&1, "id"))
|> AshHq.Github.bulk_create(AshHq.Github.Contributor, :create, |> Ash.bulk_create(AshHq.Github.Contributor, :create,
upsert?: true, upsert?: true,
upsert_fields: [:order, :login, :avatar_url, :html_url], upsert_fields: [:order, :login, :avatar_url, :html_url],
return_errors?: true, return_errors?: true,

View file

@ -1,10 +1,12 @@
defmodule AshHq.Github.Contributor do defmodule AshHq.Github.Contributor do
@moduledoc "A contributor to any package deployed on Ash HQ." @moduledoc "A contributor to any package deployed on Ash HQ."
use Ash.Resource, use Ash.Resource,
domain: AshHq.Github,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
extensions: [AshOban] extensions: [AshOban]
actions do actions do
default_accept :*
defaults [:create, :read, :update, :destroy] defaults [:create, :read, :update, :destroy]
read :in_order do read :in_order do
@ -19,7 +21,7 @@ defmodule AshHq.Github.Contributor do
end end
oban do oban do
api AshHq.Github domain AshHq.Github
scheduled_actions do scheduled_actions do
schedule :import, "0 */6 * * *" do schedule :import, "0 */6 * * *" do
@ -34,10 +36,10 @@ defmodule AshHq.Github.Contributor do
writable? true writable? true
end end
attribute :login, :string, allow_nil?: false attribute :login, :string, allow_nil?: false, public?: true
attribute :avatar_url, :string, allow_nil?: false attribute :avatar_url, :string, allow_nil?: false, public?: true
attribute :html_url, :string, allow_nil?: false attribute :html_url, :string, allow_nil?: false, public?: true
attribute :order, :integer, allow_nil?: false attribute :order, :integer, allow_nil?: false, public?: true
end end
postgres do postgres do
@ -46,7 +48,6 @@ defmodule AshHq.Github.Contributor do
end end
code_interface do code_interface do
define_for AshHq.Github
define :in_order define :in_order
end end

View file

@ -1,6 +1,6 @@
defmodule AshHq.Github do defmodule AshHq.Github do
@moduledoc "Api for interacting with data synchronized from github." @moduledoc "Domain for interacting with data synchronized from github."
use Ash.Api use Ash.Domain
resources do resources do
resource AshHq.Github.Contributor resource AshHq.Github.Contributor

View file

@ -1,5 +1,5 @@
defmodule AshHq.MailingList.EmailNotifier do defmodule AshHq.MailingList.EmailNotifier do
@moduledoc "Sends emails from events in the MailingList api" @moduledoc "Sends emails from events in the MailingList domain"
use Ash.Notifier use Ash.Notifier
def notify(%Ash.Notifier.Notification{ def notify(%Ash.Notifier.Notification{

View file

@ -2,9 +2,9 @@ defmodule AshHq.MailingList do
@moduledoc """ @moduledoc """
Handles documentation data. Handles documentation data.
""" """
use Ash.Api, otp_app: :ash_hq use Ash.Domain, otp_app: :ash_hq
resources do resources do
registry AshHq.MailingList.Registry resource AshHq.MailingList.Email
end end
end end

View file

@ -1,9 +0,0 @@
defmodule AshHq.MailingList.Registry do
@moduledoc false
use Ash.Registry,
extensions: [Ash.Registry.ResourceValidations]
entries do
entry AshHq.MailingList.Email
end
end

View file

@ -2,10 +2,12 @@ defmodule AshHq.MailingList.Email do
@moduledoc false @moduledoc false
use Ash.Resource, use Ash.Resource,
domain: AshHq.MailingList,
data_layer: AshPostgres.DataLayer, data_layer: AshPostgres.DataLayer,
notifiers: AshHq.MailingList.EmailNotifier notifiers: AshHq.MailingList.EmailNotifier
actions do actions do
default_accept :*
defaults [:create, :read] defaults [:create, :read]
end end
@ -13,6 +15,7 @@ defmodule AshHq.MailingList.Email do
uuid_primary_key :id uuid_primary_key :id
attribute :email, :ci_string do attribute :email, :ci_string do
public? true
allow_nil? false allow_nil? false
end end
@ -25,8 +28,6 @@ defmodule AshHq.MailingList.Email do
end end
code_interface do code_interface do
define_for AshHq.MailingList
define :all, action: :read define :all, action: :read
end end

View file

@ -13,12 +13,4 @@ defmodule AshHqWeb.LiveUserAuth do
{:cont, assign(socket, :current_user, nil)} {:cont, assign(socket, :current_user, nil)}
end end
end end
def on_mount(:live_user_required, _params, _session, socket) do
if socket.assigns[:current_user] do
{:cont, socket}
else
{:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")}
end
end
end end

View file

@ -224,7 +224,7 @@ defmodule AshHqWeb.Pages.Docs do
|> load_for_search() |> load_for_search()
new_libraries = new_libraries =
AshHq.Docs.load!(socket.assigns.libraries, versions: [guides: guides_query]) Ash.load!(socket.assigns.libraries, versions: [guides: guides_query])
assign(socket, :libraries, new_libraries) assign(socket, :libraries, new_libraries)
end end
@ -331,7 +331,7 @@ defmodule AshHqWeb.Pages.Docs do
resource resource
|> Ash.Query.select(field) |> Ash.Query.select(field)
|> Ash.Query.filter(id == ^record.id) |> Ash.Query.filter(id == ^record.id)
|> AshHq.Docs.read_one!() |> Ash.read_one!()
|> Map.get(field) |> Map.get(field)
Map.put(record, field, value) Map.put(record, field, value)

View file

@ -97,7 +97,7 @@ defmodule AshHqWeb.Pages.Forum do
|> Ash.Query.filter(channel_id == ^socket.assigns.channel.id) |> Ash.Query.filter(channel_id == ^socket.assigns.channel.id)
|> Ash.Query.select(:name) |> Ash.Query.select(:name)
|> Ash.Query.sort(:name) |> Ash.Query.sort(:name)
|> AshHq.Discord.read!() |> Ash.read!()
|> Enum.map(&to_string(&1.name)) |> Enum.map(&to_string(&1.name))
assign(socket, :tags, tags) assign(socket, :tags, tags)

View file

@ -489,7 +489,6 @@ defmodule AshHqWeb.Pages.Home do
contributors: contributors, contributors: contributors,
email_form: email_form:
AshPhoenix.Form.for_create(AshHq.MailingList.Email, :create, AshPhoenix.Form.for_create(AshHq.MailingList.Email, :create,
api: AshHq.MailingList,
upsert?: true, upsert?: true,
upsert_identity: :unique_email upsert_identity: :unique_email
) )
@ -638,6 +637,7 @@ defmodule AshHqWeb.Pages.Home do
@post_example """ @post_example """
defmodule Example.Post do defmodule Example.Post do
use Ash.Resource, use Ash.Resource,
domain: Example,
data_layer: AshPostgres.DataLayer data_layer: AshPostgres.DataLayer
resource do resource do

View file

@ -3,8 +3,7 @@ defmodule AshHqWeb.SessionPlug do
@behaviour Plug @behaviour Plug
@cookies_to_replicate [ @cookies_to_replicate [
"theme", "theme"
"selected_types"
] ]
def init(_), do: [] def init(_), do: []

View file

@ -9,7 +9,7 @@ defmodule AshHqWeb.RedirectToHex do
AshHq.Docs.Module AshHq.Docs.Module
|> Ash.Query.filter(name == ^dsl_target or sanitized_name == ^dsl_target) |> Ash.Query.filter(name == ^dsl_target or sanitized_name == ^dsl_target)
|> Ash.Query.load(to_load) |> Ash.Query.load(to_load)
|> AshHq.Docs.read_one() |> Ash.read_one()
|> case do |> case do
{:ok, module} when not is_nil(module) -> {:ok, module} when not is_nil(module) ->
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))} {:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
@ -30,7 +30,7 @@ defmodule AshHqWeb.RedirectToHex do
AshHq.Docs.MixTask AshHq.Docs.MixTask
|> Ash.Query.filter(name == ^mix_task or sanitized_name == ^mix_task) |> Ash.Query.filter(name == ^mix_task or sanitized_name == ^mix_task)
|> Ash.Query.load(to_load) |> Ash.Query.load(to_load)
|> AshHq.Docs.read_one() |> Ash.read_one()
|> case do |> case do
{:ok, module} when not is_nil(module) -> {:ok, module} when not is_nil(module) ->
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))} {:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
@ -51,7 +51,7 @@ defmodule AshHqWeb.RedirectToHex do
AshHq.Docs.Module AshHq.Docs.Module
|> Ash.Query.filter(name == ^module or sanitized_name == ^module) |> Ash.Query.filter(name == ^module or sanitized_name == ^module)
|> Ash.Query.load(to_load) |> Ash.Query.load(to_load)
|> AshHq.Docs.read_one() |> Ash.read_one()
|> case do |> case do
{:ok, module} when not is_nil(module) -> {:ok, module} when not is_nil(module) ->
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))} {:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}
@ -67,7 +67,7 @@ defmodule AshHqWeb.RedirectToHex do
AshHq.Docs.Module AshHq.Docs.Module
|> Ash.Query.filter(name == ^module or sanitized_name == ^module) |> Ash.Query.filter(name == ^module or sanitized_name == ^module)
|> Ash.Query.load(to_load) |> Ash.Query.load(to_load)
|> AshHq.Docs.read_one() |> Ash.read_one()
|> case do |> case do
{:ok, module} when not is_nil(module) -> {:ok, module} when not is_nil(module) ->
{:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))} {:halt, redirect(socket, external: AshHqWeb.DocRoutes.doc_link(module))}

View file

@ -10,12 +10,10 @@ defmodule AshHqWeb.Router do
plug(:put_root_layout, {AshHqWeb.LayoutView, :root}) plug(:put_root_layout, {AshHqWeb.LayoutView, :root})
plug(:protect_from_forgery) plug(:protect_from_forgery)
plug(AshHqWeb.SessionPlug) plug(AshHqWeb.SessionPlug)
plug(:load_from_session)
end end
pipeline :api do pipeline :api do
plug(:accepts, ["json"]) plug(:accepts, ["json"])
plug(:load_from_bearer)
end end
pipeline :admin_basic_auth do pipeline :admin_basic_auth do

View file

@ -2,9 +2,9 @@ defmodule AshHqWeb.Schema do
@moduledoc "The absinthe graphql schema" @moduledoc "The absinthe graphql schema"
use Absinthe.Schema use Absinthe.Schema
@apis [AshHq.Docs] @domains [AshHq.Docs]
use AshGraphql, apis: @apis use AshGraphql, domains: @domains
query do query do
end end

View file

@ -1,18 +1,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="<%= "#{@configured_theme}" %>"> <html lang="en" class={@configured_theme}>
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<%= csrf_meta_tag() %> <%= csrf_meta_tag() %>
<%= live_title_tag assigns[:page_title] || "Ash Framework" %> <.live_title>
<%= assigns[:page_title] || "Ash Framework" %>
</.live_title>
<%= if Application.get_env(:ash_hq, :analytics?) do %> <%= if Application.get_env(:ash_hq, :analytics?) do %>
<script defer data-domain="ash-hq.org" src="https://plausible.io/js/plausible.js"></script> <script defer data-domain="ash-hq.org" src="https://plausible.io/js/plausible.js"></script>
<% end %> <% end %>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" /> <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.3/cookieconsent.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.6.2/jquery.min.js"></script>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/assets/app.css") %>"/> <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
</head> </head>
<body class="h-full"> <body class="h-full">
<%= case live_flash(@flash, :info) do %> <%= case live_flash(@flash, :info) do %>
@ -34,6 +36,6 @@
<%= if @live_action == :media do %> <%= if @live_action == :media do %>
<script src="https://platform.twitter.com/widgets.js" charset="utf-8" ></script> <script src="https://platform.twitter.com/widgets.js" charset="utf-8" ></script>
<% end %> <% end %>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/assets/app.js") %>"></script> <script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
</body> </body>
</html> </html>

View file

@ -41,7 +41,6 @@ defmodule AshHqWeb.AppViewLive do
uri={@uri} uri={@uri}
close={close_search()} close={close_search()}
libraries={@libraries} libraries={@libraries}
selected_types={@selected_types}
change_types="change-types" change_types="change-types"
change_versions="change-versions" change_versions="change-versions"
remove_version="remove_version" remove_version="remove_version"
@ -158,23 +157,6 @@ defmodule AshHqWeb.AppViewLive do
{:noreply, socket} {:noreply, socket}
end end
def handle_event("change-types", %{"types" => types}, socket) do
types =
types
|> Enum.filter(fn {_, value} ->
value == "true"
end)
|> Enum.map(&elem(&1, 0))
{:noreply,
socket
|> assign(
:selected_types,
types
)
|> push_event("selected-types", %{types: types})}
end
def handle_event("toggle_theme", _, socket) do def handle_event("toggle_theme", _, socket) do
theme = theme =
case socket.assigns.configured_theme do case socket.assigns.configured_theme do
@ -206,19 +188,6 @@ defmodule AshHqWeb.AppViewLive do
configured_theme = session["theme"] || "system" configured_theme = session["theme"] || "system"
all_types = AshHq.Docs.Extensions.Search.Types.types()
selected_types =
case session["selected_types"] do
nil ->
AshHq.Docs.Extensions.Search.Types.types()
types ->
types
|> String.split(",")
|> Enum.filter(&(&1 in all_types))
end
versions_query = versions_query =
AshHq.Docs.LibraryVersion AshHq.Docs.LibraryVersion
|> Ash.Query.sort(version: :desc) |> Ash.Query.sort(version: :desc)
@ -228,12 +197,7 @@ defmodule AshHqWeb.AppViewLive do
{:ok, {:ok,
socket socket
|> assign(:libraries, libraries) |> assign(:libraries, libraries)
|> assign( |> assign(configured_theme: configured_theme)}
:selected_types,
selected_types
)
|> assign(configured_theme: configured_theme)
|> push_event("selected_types", %{types: selected_types})}
end end
def toggle_search(js \\ %JS{}) do def toggle_search(js \\ %JS{}) do

View file

@ -39,7 +39,8 @@ defmodule AshHq.MixProject do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
{:ash, "~> 3.0.0-rc"}, # {:ash, "~> 3.0.0-rc"},
{:ash, path: "../../ash/ash", override: true},
{:ash_postgres, "~> 2.0.0-rc"}, {:ash_postgres, "~> 2.0.0-rc"},
{:ash_admin, "~> 0.10.10-rc"}, {:ash_admin, "~> 0.10.10-rc"},
{:ash_phoenix, "~> 2.0.0-rc"}, {:ash_phoenix, "~> 2.0.0-rc"},
@ -99,6 +100,7 @@ defmodule AshHq.MixProject do
{:phoenix_html, "~> 4.0"}, {:phoenix_html, "~> 4.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev}, {:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.18"}, {:phoenix_live_view, "~> 0.18"},
{:html_entities, "~> 0.5"},
# locked for compatibility # locked for compatibility
{:finch, "~> 0.10"}, {:finch, "~> 0.10"},
{:floki, "~> 0.30"}, {:floki, "~> 0.30"},

View file

@ -44,7 +44,7 @@
"equivalex": {:hex, :equivalex, "1.0.3", "170d9a82ae066e0020dfe1cf7811381669565922eb3359f6c91d7e9a1124ff74", [:mix], [], "hexpm", "46fa311adb855117d36e461b9c0ad2598f72110ad17ad73d7533c78020e045fc"}, "equivalex": {:hex, :equivalex, "1.0.3", "170d9a82ae066e0020dfe1cf7811381669565922eb3359f6c91d7e9a1124ff74", [:mix], [], "hexpm", "46fa311adb855117d36e461b9c0ad2598f72110ad17ad73d7533c78020e045fc"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
"ets": {:hex, :ets, "0.8.1", "8ff9bcda5682b98493f8878fc9dbd990e48d566cba8cce59f7c2a78130da29ea", [:mix], [], "hexpm", "6be41b50adb5bc5c43626f25ea2d0af1f4a242fb3fad8d53f0c67c20b78915cc"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"},
"ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"},
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"}, "ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
"excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"},
@ -61,6 +61,7 @@
"hackney": {:hex, :hackney, "1.17.1", "08463f93d2cc1a03817bf28d8dae6021543f773bd436c9377047224856c4422c", [:rebar3], [{:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "~> 3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "d2cba9e3c8103ad0320623e9f1c33e8d378a15eaabe2ee8ae441898f3d35a18c"}, "hackney": {:hex, :hackney, "1.17.1", "08463f93d2cc1a03817bf28d8dae6021543f773bd436c9377047224856c4422c", [:rebar3], [{:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "~> 3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "d2cba9e3c8103ad0320623e9f1c33e8d378a15eaabe2ee8ae441898f3d35a18c"},
"haystack": {:hex, :haystack, "0.1.0", "6cb9c72caf40ed4a5f9a094e6b09993c68c3fda0e01280c60c331a19860c504c", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:stemmer, "~> 1.1", [hex: :stemmer, repo: "hexpm", optional: false]}], "hexpm", "27a582513ef933c1b11345b96f8d41ee137d03b25312bd85068ffe8fec503635"}, "haystack": {:hex, :haystack, "0.1.0", "6cb9c72caf40ed4a5f9a094e6b09993c68c3fda0e01280c60c331a19860c504c", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:stemmer, "~> 1.1", [hex: :stemmer, repo: "hexpm", optional: false]}], "hexpm", "27a582513ef933c1b11345b96f8d41ee137d03b25312bd85068ffe8fec503635"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"json_xema": {:hex, :json_xema, "0.4.2", "85de190f597a98ce9da436b8a59c97ef561a6ab6017255df8b494babefd6fb10", [:mix], [{:conv_case, "~> 0.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:xema, "~> 0.11", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "5516213758667d21669e0d63ea287238d277519527bac6c02140a5e34c1fda80"}, "json_xema": {:hex, :json_xema, "0.4.2", "85de190f597a98ce9da436b8a59c97ef561a6ab6017255df8b494babefd6fb10", [:mix], [{:conv_case, "~> 0.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:xema, "~> 0.11", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "5516213758667d21669e0d63ea287238d277519527bac6c02140a5e34c1fda80"},