diff --git a/lib/kaffy/resource_callbacks.ex b/lib/kaffy/resource_callbacks.ex
index 551ed0ad..962ea7ed 100644
--- a/lib/kaffy/resource_callbacks.ex
+++ b/lib/kaffy/resource_callbacks.ex
@@ -5,7 +5,7 @@ defmodule Kaffy.ResourceCallbacks do
def create_callbacks(conn, resource, changes) do
changeset = Kaffy.ResourceAdmin.create_changeset(resource, changes)
- repo = Kaffy.Utils.repo()
+ repo = Kaffy.Utils.repo(resource)
repo.transaction(fn ->
result =
@@ -28,7 +28,7 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
- Kaffy.Utils.repo().insert(changeset)
+ Kaffy.Utils.repo(resource).insert(changeset)
unexpected_error ->
{:error, unexpected_error}
@@ -37,7 +37,7 @@ defmodule Kaffy.ResourceCallbacks do
def update_callbacks(conn, resource, entry, changes) do
changeset = Kaffy.ResourceAdmin.update_changeset(resource, entry, changes)
- repo = Kaffy.Utils.repo()
+ repo = Kaffy.Utils.repo(resource)
repo.transaction(fn ->
result =
@@ -60,7 +60,7 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
- Kaffy.Utils.repo().update(changeset)
+ Kaffy.Utils.repo(resource).update(changeset)
unexpected_error ->
{:error, unexpected_error}
@@ -68,7 +68,7 @@ defmodule Kaffy.ResourceCallbacks do
end
def delete_callbacks(conn, resource, entry) do
- repo = Kaffy.Utils.repo()
+ repo = Kaffy.Utils.repo(resource)
repo.transaction(fn ->
result =
@@ -163,7 +163,7 @@ defmodule Kaffy.ResourceCallbacks do
{:ok, entry}
else
{:error, :not_found} ->
- Kaffy.Utils.repo().delete(changeset)
+ Kaffy.Utils.repo(resource).delete(changeset)
unexpected_error ->
{:error, unexpected_error}
diff --git a/lib/kaffy/resource_form.ex b/lib/kaffy/resource_form.ex
index dfbe4d2d..2955a52a 100644
--- a/lib/kaffy/resource_form.ex
+++ b/lib/kaffy/resource_form.ex
@@ -29,13 +29,13 @@ defmodule Kaffy.ResourceForm do
)
true ->
- build_html_input(resource[:schema], form, field, type, [])
+ build_html_input(resource, resource[:schema], form, field, type, [])
end
end
- def form_field(changeset, form, field, opts \\ [])
+ def form_field(resource, changeset, form, field, opts \\ [])
- def form_field(changeset, form, {field, options}, opts) do
+ def form_field(resource, changeset, form, {field, options}, opts) do
options = options || %{}
type =
@@ -50,7 +50,7 @@ defmodule Kaffy.ResourceForm do
end
permission =
- case is_nil(changeset.data.id) do
+ case !Map.has_key?(changeset.data, :id) || is_nil(changeset.data.id) do
true -> Map.get(options, :create, :editable)
false -> Map.get(options, :update, :editable)
end
@@ -62,16 +62,24 @@ defmodule Kaffy.ResourceForm do
select(form, field, choices, class: "custom-select")
true ->
- build_html_input(changeset.data, form, field, type, opts, permission == :readonly)
+ build_html_input(
+ resource,
+ changeset.data,
+ form,
+ field,
+ type,
+ opts,
+ permission == :readonly
+ )
end
end
- def form_field(changeset, form, field, opts) do
+ def form_field(resource, changeset, form, field, opts) do
type = Kaffy.ResourceSchema.field_type(changeset.data.__struct__, field)
- build_html_input(changeset.data, form, field, type, opts)
+ build_html_input(resource, changeset.data, form, field, type, opts)
end
- defp build_html_input(schema, form, field, type, opts, readonly \\ false) do
+ defp build_html_input(resource, schema, form, field, type, opts, readonly \\ false) do
data = schema
{conn, opts} = Keyword.pop(opts, :conn)
opts = Keyword.put(opts, :readonly, readonly)
@@ -91,7 +99,7 @@ defmodule Kaffy.ResourceForm do
[
[
form_label(fp, f),
- form_field(embed_changeset, fp, f, class: "form-control")
+ form_field(resource, embed_changeset, fp, f, class: "form-control")
]
| all
]
@@ -104,13 +112,13 @@ defmodule Kaffy.ResourceForm do
:id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
true -> text_input(form, field, opts)
- false -> text_or_assoc(conn, schema, form, field, opts)
+ false -> text_or_assoc(conn, resource, form, field, opts)
end
:binary_id ->
case Kaffy.ResourceSchema.primary_key(schema) == [field] do
true -> text_input(form, field, opts)
- false -> text_or_assoc(conn, schema, form, field, opts)
+ false -> text_or_assoc(conn, resource, form, field, opts)
end
:string ->
@@ -240,7 +248,9 @@ defmodule Kaffy.ResourceForm do
]
end
- defp text_or_assoc(conn, schema, form, field, opts) do
+ defp text_or_assoc(conn, resource, form, field, opts) do
+ schema = resource[:schema]
+
actual_assoc =
Enum.filter(Kaffy.ResourceSchema.associations(schema), fn a ->
Kaffy.ResourceSchema.association(schema, a).owner_key == field
@@ -256,7 +266,8 @@ defmodule Kaffy.ResourceForm do
case field_no_id in Kaffy.ResourceSchema.associations(schema) do
true ->
assoc = Kaffy.ResourceSchema.association_schema(schema, field_no_id)
- option_count = Kaffy.ResourceQuery.cached_total_count(assoc, true, assoc)
+ assoc_resource = Kaffy.Utils.get_resource_from_schema(conn, assoc)
+ option_count = Kaffy.ResourceQuery.cached_total_count(assoc_resource, true, assoc)
case option_count > 100 do
true ->
@@ -291,7 +302,7 @@ defmodule Kaffy.ResourceForm do
end
false ->
- options = Kaffy.Utils.repo().all(assoc)
+ options = Kaffy.Utils.repo(resource).all(assoc)
fields = Kaffy.ResourceSchema.fields(assoc)
@@ -335,6 +346,11 @@ defmodule Kaffy.ResourceForm do
nil ->
{nil, ""}
+ errors when is_map(errors) ->
+ error_msg = Kaffy.ResourceAdmin.humanize_term(field) <> " has multiple errors!"
+
+ {error_msg, "is-invalid"}
+
messages ->
error_msg =
Kaffy.ResourceAdmin.humanize_term(field) <> " " <> Enum.join(messages, ", ") <> "!"
@@ -356,7 +372,7 @@ defmodule Kaffy.ResourceForm do
defp build_changeset_value(value), do: to_string(value)
- def kaffy_input(conn, changeset, form, field, options) do
+ def kaffy_input(conn, resource, changeset, form, field, options) do
ft = Kaffy.ResourceSchema.field_type(changeset.data.__struct__, field)
case Kaffy.Utils.is_module(ft) && Keyword.has_key?(ft.__info__(:functions), :render_form) do
@@ -371,7 +387,7 @@ defmodule Kaffy.ResourceForm do
label_tag = if ft != :boolean, do: form_label(form, {field, options}), else: ""
field_tag =
- form_field(changeset, form, {field, options},
+ form_field(resource, changeset, form, {field, options},
class: "form-control #{error_class}",
conn: conn
)
diff --git a/lib/kaffy/resource_query.ex b/lib/kaffy/resource_query.ex
index e2a3995e..56c57f83 100644
--- a/lib/kaffy/resource_query.ex
+++ b/lib/kaffy/resource_query.ex
@@ -26,10 +26,10 @@ defmodule Kaffy.ResourceQuery do
)
custom_query = Kaffy.ResourceAdmin.custom_index_query(conn, resource, paged)
- current_page = Kaffy.Utils.repo().all(custom_query)
+ current_page = Kaffy.Utils.repo(resource).all(custom_query)
do_cache = if search == "" and Enum.empty?(filtered_fields), do: true, else: false
- all_count = cached_total_count(schema, do_cache, all)
+ all_count = cached_total_count(resource, do_cache, all)
{all_count, current_page}
end
@@ -48,7 +48,7 @@ defmodule Kaffy.ResourceQuery do
schema = resource[:schema]
query = from(s in schema, where: s.id == ^id)
custom_query = Kaffy.ResourceAdmin.custom_show_query(conn, resource, query)
- Kaffy.Utils.repo().one(custom_query)
+ Kaffy.Utils.repo(resource).one(custom_query)
end
def fetch_list(_, [""]), do: []
@@ -57,13 +57,15 @@ defmodule Kaffy.ResourceQuery do
schema = resource[:schema]
from(s in schema, where: s.id in ^ids)
- |> Kaffy.Utils.repo().all()
+ |> Kaffy.Utils.repo(resource).all()
end
- def total_count(schema, do_cache, query) do
+ def total_count(resource, do_cache, query) do
+ schema = resource[:schema]
+
result =
from(s in query, select: fragment("count(*)"))
- |> Kaffy.Utils.repo().one()
+ |> Kaffy.Utils.repo(resource).one()
if do_cache and result > 100_000 do
Kaffy.Cache.Client.add_cache(schema, "count", result, 600)
@@ -72,10 +74,11 @@ defmodule Kaffy.ResourceQuery do
result
end
- def cached_total_count(schema, false, query), do: total_count(schema, false, query)
+ def cached_total_count(resource, false, query), do: total_count(resource, false, query)
- def cached_total_count(schema, do_cache, query) do
- Kaffy.Cache.Client.get_cache(schema, "count") || total_count(schema, do_cache, query)
+ def cached_total_count(resource, do_cache, query) do
+ Kaffy.Cache.Client.get_cache(resource[:schema], "count") ||
+ total_count(resource, do_cache, query)
end
defp get_filter_fields(params, resource) do
diff --git a/lib/kaffy/utils.ex b/lib/kaffy/utils.ex
index 5542273e..b729455f 100644
--- a/lib/kaffy/utils.ex
+++ b/lib/kaffy/utils.ex
@@ -50,6 +50,14 @@ defmodule Kaffy.Utils do
end
end
+ @doc """
+ Returns the repo module specified by the resource
+ """
+ @spec repo(String.t()) :: atom()
+ def repo(resource) do
+ resource[:repo] || repo()
+ end
+
@doc """
Returns the version of the provided app.
@@ -121,6 +129,14 @@ defmodule Kaffy.Utils do
end
end
+ @spec set_dynamic_repo(Plug.Conn.t()) :: atom() | pid() | nil
+ def set_dynamic_repo(conn) do
+ case env(:set_dynamic_repo) do
+ f when is_function(f) -> f.(conn)
+ _ -> nil
+ end
+ end
+
@doc """
Returns a list of contexts as atoms.
@@ -211,6 +227,31 @@ defmodule Kaffy.Utils do
get_in(full_resources(conn), [context, :resources, resource])
end
+ @doc """
+ Returns the resource entry from the schema.
+
+ Example:
+
+ iex> get_resource_from_schema(conn, MyApp.Blog.Post)
+ [schema: MyApp.Blog.Post, admin: MyApp.Blog.PostAdmin]
+ """
+ @spec get_resource_from_schema(Plug.Conn.t(), module()) :: list()
+ def get_resource_from_schema(conn, schema) do
+ full_resources(conn)
+ |> Enum.reduce_while(nil, fn {_, props}, acc ->
+ props[:resources]
+ |> Enum.reduce(fn {_name, resource_props}, _ ->
+ if resource_props[:schema] == schema do
+ resource_props
+ end
+ end)
+ |> case do
+ nil -> {:cont, acc}
+ resource -> {:halt, resource}
+ end
+ end)
+ end
+
@doc """
Returns all the schemas for the given context.
@@ -340,7 +381,15 @@ defmodule Kaffy.Utils do
end
end)
- %{stylesheets: stylesheets, javascripts: javascripts}
+ navigation_extras =
+ Enum.map(exts, fn ext ->
+ case function_exported?(ext, :navigation_extras, 1) do
+ true -> ext.navigation_extras(conn)
+ false -> []
+ end
+ end)
+
+ %{stylesheets: stylesheets, javascripts: javascripts, navigation_extras: navigation_extras}
end
defp env(key, default \\ nil) do
diff --git a/lib/kaffy_web/controllers/resource_controller.ex b/lib/kaffy_web/controllers/resource_controller.ex
index 2d84c5f3..9fe8122f 100644
--- a/lib/kaffy_web/controllers/resource_controller.ex
+++ b/lib/kaffy_web/controllers/resource_controller.ex
@@ -15,6 +15,7 @@ defmodule KaffyWeb.ResourceController do
"pick" => _field
} = params
) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
@@ -52,6 +53,7 @@ defmodule KaffyWeb.ResourceController do
end
def index(conn, %{"context" => context, "resource" => resource} = params) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
@@ -89,6 +91,7 @@ defmodule KaffyWeb.ResourceController do
end
def show(conn, %{"context" => context, "resource" => resource, "id" => id}) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
schema = my_resource[:schema]
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource)
@@ -121,6 +124,7 @@ defmodule KaffyWeb.ResourceController do
end
def update(conn, %{"context" => context, "resource" => resource, "id" => id} = params) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
schema = my_resource[:schema]
params = Kaffy.ResourceParams.decode_map_fields(resource, schema, params)
@@ -200,6 +204,7 @@ defmodule KaffyWeb.ResourceController do
end
def new(conn, %{"context" => context, "resource" => resource}) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
resource_name = Kaffy.ResourceAdmin.singular_name(my_resource)
@@ -222,6 +227,7 @@ defmodule KaffyWeb.ResourceController do
end
def create(conn, %{"context" => context, "resource" => resource} = params) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
params = Kaffy.ResourceParams.decode_map_fields(resource, my_resource[:schema], params)
changes = Map.get(params, resource, %{})
@@ -281,6 +287,7 @@ defmodule KaffyWeb.ResourceController do
end
def delete(conn, %{"context" => context, "resource" => resource, "id" => id}) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
case can_proceed?(my_resource, conn) do
@@ -318,6 +325,7 @@ defmodule KaffyWeb.ResourceController do
"id" => id,
"action_key" => action_key
}) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
entry = Kaffy.ResourceQuery.fetch_resource(conn, my_resource, id)
actions = Kaffy.ResourceAdmin.resource_actions(my_resource, conn)
@@ -342,6 +350,7 @@ defmodule KaffyWeb.ResourceController do
conn,
%{"context" => context, "resource" => resource, "action_key" => action_key} = params
) do
+ Kaffy.Utils.set_dynamic_repo(conn)
my_resource = Kaffy.Utils.get_resource(conn, context, resource)
ids = Map.get(params, "ids", "") |> String.split(",")
entries = Kaffy.ResourceQuery.fetch_list(my_resource, ids)
diff --git a/lib/kaffy_web/templates/layout/app.html.eex b/lib/kaffy_web/templates/layout/app.html.eex
index 1aa5308c..b479209f 100644
--- a/lib/kaffy_web/templates/layout/app.html.eex
+++ b/lib/kaffy_web/templates/layout/app.html.eex
@@ -26,7 +26,7 @@
<% end %>
-