changed
CHANGELOG.md
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+ ## [0.3.0] - 2020-02-04
|
9
|
+
|
10
|
+ ### Added
|
11
|
+
|
12
|
+ - `view_module` option to `Adminable.Plug` to allow users to use their own views and templates
|
13
|
+ - `mix adminable.gen.view` to export Adminable's view and templates for modification
|
14
|
+
|
8
15
|
## [0.2.0] - 2019-12-23
|
9
16
|
|
10
17
|
### Updated
|
changed
README.md
|
@@ -12,7 +12,7 @@ by adding `adminable` to your list of dependencies in `mix.exs`:
|
12
12
|
```elixir
|
13
13
|
def deps do
|
14
14
|
[
|
15
|
- {:adminable, "~> 0.1.0"}
|
15
|
+ {:adminable, "~> 0.3.0"}
|
16
16
|
]
|
17
17
|
end
|
18
18
|
```
|
|
@@ -46,8 +46,25 @@ scope "/admin" do
|
46
46
|
forward("/", Adminable.Plug, [
|
47
47
|
otp_app: :my_app,
|
48
48
|
repo: MyApp.Repo,
|
49
|
- schemas: [MyApp.User]
|
49
|
+ schemas: [MyApp.User],
|
50
|
+ view_module: MyAppWeb.Adminable.AdminView
|
50
51
|
layout: {MyAppWeb.LayoutView, "app.html"}
|
51
52
|
])
|
52
53
|
end
|
53
54
|
```
|
55
|
+
|
56
|
+ Arguments
|
57
|
+
|
58
|
+ - `otp_app` - Your app
|
59
|
+ - `repo` - Your app's Repo
|
60
|
+ - `schemas` - The schemas to make Admin sections for
|
61
|
+ - `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
|
62
|
+ - `layout` - (Optional) The layout to use
|
63
|
+
|
64
|
+ ## Exporting View and Templates
|
65
|
+
|
66
|
+ To export Adminable's AdminView and templates for modification, run:
|
67
|
+
|
68
|
+ ```bash
|
69
|
+ mix adminable.gen.view MyWebModule
|
70
|
+ ```
|
changed
hex_metadata.config
|
@@ -4,11 +4,13 @@
|
4
4
|
<<"Create admin interfaces for Ecto schemas in Phoenix apps">>}.
|
5
5
|
{<<"elixir">>,<<"~> 1.8">>}.
|
6
6
|
{<<"files">>,
|
7
|
- [<<"lib">>,<<"lib/adminable.ex">>,<<"lib/adminable">>,
|
8
|
- <<"lib/adminable/router.ex">>,<<"lib/adminable/views">>,
|
9
|
- <<"lib/adminable/views/admin_view.ex">>,
|
10
|
- <<"lib/adminable/views/pagination_view.ex">>,
|
11
|
- <<"lib/adminable/views/field.ex">>,<<"lib/adminable/views/layout_view.ex">>,
|
7
|
+ [<<"lib">>,<<"lib/mix">>,<<"lib/mix/tasks">>,
|
8
|
+ <<"lib/mix/tasks/adminable.gen.view.ex">>,<<"lib/adminable.ex">>,
|
9
|
+ <<"lib/adminable">>,<<"lib/adminable/router.ex">>,
|
10
|
+ <<"lib/adminable/exporter.ex">>,<<"lib/adminable/views">>,
|
11
|
+ <<"lib/adminable/views/admin_view.ex">>,<<"lib/adminable/views/field.ex">>,
|
12
|
+ <<"lib/adminable/views/layout_view.ex">>,
|
13
|
+ <<"lib/adminable/views/view_helpers.ex">>,
|
12
14
|
<<"lib/adminable/error_helpers.ex">>,
|
13
15
|
<<"lib/adminable/admin_controller.ex">>,<<"lib/adminable/templates">>,
|
14
16
|
<<"lib/adminable/templates/layout">>,
|
|
@@ -60,4 +62,4 @@
|
60
62
|
{<<"optional">>,false},
|
61
63
|
{<<"repository">>,<<"hexpm">>},
|
62
64
|
{<<"requirement">>,<<"~> 1.0">>}]]}.
|
63
|
- {<<"version">>,<<"0.2.0">>}.
|
65
|
+ {<<"version">>,<<"0.3.0">>}.
|
changed
lib/adminable.ex
|
@@ -27,11 +27,20 @@ defmodule Adminable do
|
27
27
|
forward("/", Adminable.Plug, [
|
28
28
|
otp_app: :my_app,
|
29
29
|
repo: MyApp.Repo,
|
30
|
- schemas: [MyApp.User]
|
30
|
+ schemas: [MyApp.User],
|
31
|
+ view_module: MyAppWeb.Adminable.AdminView
|
31
32
|
layout: {MyAppWeb.LayoutView, "app.html"}
|
32
33
|
])
|
33
34
|
end
|
34
35
|
```
|
36
|
+
|
37
|
+ Arguments
|
38
|
+
|
39
|
+ * `otp_app` - Your app
|
40
|
+ * `repo` - Your app's Repo
|
41
|
+ * `schemas` - The schemas to make Admin sections for
|
42
|
+ * `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
|
43
|
+ * `layout` - (Optional) The layout to use
|
35
44
|
"""
|
36
45
|
|
37
46
|
@doc """
|
changed
lib/adminable/admin_controller.ex
|
@@ -3,7 +3,6 @@ defmodule Adminable.AdminController do
|
3
3
|
|
4
4
|
use Phoenix.Controller, namespace: Adminable
|
5
5
|
import Plug.Conn
|
6
|
- alias Adminable.Router.Helpers, as: Routes
|
7
6
|
|
8
7
|
def dashboard(conn, _params) do
|
9
8
|
schemas = Map.keys(conn.assigns.schemas)
|
|
@@ -14,6 +13,7 @@ defmodule Adminable.AdminController do
|
14
13
|
|
15
14
|
conn
|
16
15
|
|> put_layout(conn.assigns.layout)
|
16
|
+ |> put_view(conn.assigns.view_module)
|
17
17
|
|> render("dashboard.html", opts)
|
18
18
|
end
|
19
19
|
|
|
@@ -40,6 +40,7 @@ defmodule Adminable.AdminController do
|
40
40
|
|
41
41
|
conn
|
42
42
|
|> put_layout(conn.assigns.layout)
|
43
|
+ |> put_view(conn.assigns.view_module)
|
43
44
|
|> render("index.html", opts)
|
44
45
|
end
|
45
46
|
|
|
@@ -56,6 +57,7 @@ defmodule Adminable.AdminController do
|
56
57
|
|
57
58
|
conn
|
58
59
|
|> put_layout(conn.assigns.layout)
|
60
|
+ |> put_view(conn.assigns.view_module)
|
59
61
|
|> render("new.html", opts)
|
60
62
|
end
|
61
63
|
|
|
@@ -70,7 +72,7 @@ defmodule Adminable.AdminController do
|
70
72
|
{:ok, _created} ->
|
71
73
|
conn
|
72
74
|
|> put_flash(:info, "#{String.capitalize(schema)} created!")
|
73
|
- |> redirect(to: Routes.admin_path(conn, :index, schema))
|
75
|
+ |> redirect(to: Adminable.Router.Helpers.admin_path(conn, :index, schema))
|
74
76
|
|
75
77
|
{:error, changeset} ->
|
76
78
|
opts = [
|
|
@@ -83,6 +85,7 @@ defmodule Adminable.AdminController do
|
83
85
|
|> put_flash(:error, "#{String.capitalize(schema)} failed to create!")
|
84
86
|
|> put_status(:unprocessable_entity)
|
85
87
|
|> put_layout(conn.assigns.layout)
|
88
|
+ |> put_view(conn.assigns.view_module)
|
86
89
|
|> render("new.html", opts)
|
87
90
|
end
|
88
91
|
end
|
|
@@ -105,6 +108,7 @@ defmodule Adminable.AdminController do
|
105
108
|
|
106
109
|
conn
|
107
110
|
|> put_layout(conn.assigns.layout)
|
111
|
+ |> put_view(conn.assigns.view_module)
|
108
112
|
|> render("edit.html", opts)
|
109
113
|
end
|
110
114
|
|
|
@@ -119,7 +123,7 @@ defmodule Adminable.AdminController do
|
119
123
|
{:ok, _updated_model} ->
|
120
124
|
conn
|
121
125
|
|> put_flash(:info, "#{String.capitalize(schema)} ID #{pk} updated!")
|
122
|
- |> redirect(to: Routes.admin_path(conn, :index, schema))
|
126
|
+ |> redirect(to: Adminable.Router.Helpers.admin_path(conn, :index, schema))
|
123
127
|
|
124
128
|
{:error, changeset} ->
|
125
129
|
opts = [
|
|
@@ -133,6 +137,7 @@ defmodule Adminable.AdminController do
|
133
137
|
|> put_flash(:error, "#{String.capitalize(schema)} ID #{pk} failed to update!")
|
134
138
|
|> put_status(:unprocessable_entity)
|
135
139
|
|> put_layout(conn.assigns.layout)
|
140
|
+ |> put_view(conn.assigns.view_module)
|
136
141
|
|> render("edit.html", opts)
|
137
142
|
end
|
138
143
|
end
|
added
lib/adminable/exporter.ex
|
@@ -0,0 +1,61 @@
|
1
|
+ defmodule Adminable.Exporter do
|
2
|
+ @moduledoc """
|
3
|
+ Exports templates and a view module.
|
4
|
+ This allows for apps that use Adminable to modify templates
|
5
|
+ to their liking.
|
6
|
+ """
|
7
|
+
|
8
|
+ template_paths = "lib/adminable/templates/admin/**/*.html.eex" |> Path.wildcard() |> Enum.sort()
|
9
|
+
|
10
|
+ templates =
|
11
|
+ for template_path <- template_paths do
|
12
|
+ @external_resource Path.relative_to_cwd(template_path)
|
13
|
+ {Path.basename(template_path), File.read!(template_path)}
|
14
|
+ end
|
15
|
+
|
16
|
+ @templates templates
|
17
|
+
|
18
|
+ def list_templates do
|
19
|
+ @templates
|
20
|
+ end
|
21
|
+
|
22
|
+ def view_module(web_module) do
|
23
|
+ """
|
24
|
+ defmodule #{inspect web_module}.Adminable.AdminView do
|
25
|
+ use #{inspect web_module}, :view
|
26
|
+ use Adminable.ViewHelpers
|
27
|
+ end
|
28
|
+ """
|
29
|
+ end
|
30
|
+
|
31
|
+ def templates_path(web_module) do
|
32
|
+ Path.join(web_module_path(web_module), "templates")
|
33
|
+ end
|
34
|
+
|
35
|
+ def views_path(web_module) do
|
36
|
+ Path.join(web_module_path(web_module), "views")
|
37
|
+ end
|
38
|
+
|
39
|
+ defp web_module_path(web_module) do
|
40
|
+ name = Phoenix.Naming.underscore(web_module)
|
41
|
+ Path.join(["lib", name])
|
42
|
+ end
|
43
|
+
|
44
|
+ def export(web_module) do
|
45
|
+ templates_path = templates_path(web_module)
|
46
|
+ views_path = views_path(web_module)
|
47
|
+
|
48
|
+ view_module = view_module(web_module)
|
49
|
+ templates = list_templates()
|
50
|
+
|
51
|
+ exported_view_module_path = Path.join([views_path, "adminable", "admin_view.ex"])
|
52
|
+ File.mkdir_p!(Path.dirname(exported_view_module_path))
|
53
|
+ File.write!(exported_view_module_path, view_module)
|
54
|
+
|
55
|
+ exported_templates_path = Path.join([templates_path, "adminable", "admin"])
|
56
|
+ File.mkdir_p!(exported_templates_path)
|
57
|
+ Enum.each(templates, fn({name, data}) ->
|
58
|
+ File.write!(Path.join(exported_templates_path, name), data)
|
59
|
+ end)
|
60
|
+ end
|
61
|
+ end
|
changed
lib/adminable/plug.ex
|
@@ -10,10 +10,20 @@ defmodule Adminable.Plug do
|
10
10
|
otp_app: :my_app,
|
11
11
|
repo: MyApp.Repo,
|
12
12
|
schemas: [MyApp.User],
|
13
|
+ view_module: MyAppWeb.Adminable.AdminView
|
13
14
|
layout: {MyAppWeb.LayoutView, "app.html"}
|
14
15
|
])
|
15
16
|
end
|
16
17
|
```
|
18
|
+
|
19
|
+ Arguments
|
20
|
+
|
21
|
+ * `otp_app` - Your app
|
22
|
+ * `repo` - Your app's Repo
|
23
|
+ * `schemas` - The schemas to make Admin sections for
|
24
|
+ * `view_module` - (Optional) The view_module to use to display pages. Uses Adminable's view module by default. You can export the view to modify using `mix adminable.gen.view MyWebModule`
|
25
|
+ * `layout` - (Optional) The layout to use
|
26
|
+
|
17
27
|
"""
|
18
28
|
|
19
29
|
def init(opts) do
|
|
@@ -24,6 +34,7 @@ defmodule Adminable.Plug do
|
24
34
|
repo = Keyword.fetch!(opts, :repo)
|
25
35
|
otp_app = Keyword.fetch!(opts, :otp_app)
|
26
36
|
schemas = Keyword.get(opts, :schemas, [])
|
37
|
+ view_module = Keyword.get(opts, :view_module, Adminable.AdminView)
|
27
38
|
layout = Keyword.get(opts, :layout, {Adminable.LayoutView, "app.html"})
|
28
39
|
|
29
40
|
schemas =
|
|
@@ -40,6 +51,7 @@ defmodule Adminable.Plug do
|
40
51
|
|> Plug.Conn.assign(:repo, repo)
|
41
52
|
|> Plug.Conn.assign(:schemas, schemas)
|
42
53
|
|> Plug.Conn.assign(:layout, layout)
|
54
|
+ |> Plug.Conn.assign(:view_module, view_module)
|
43
55
|
|> Adminable.Router.call(opts)
|
44
56
|
end
|
45
57
|
end
|
changed
lib/adminable/templates/admin/_pagination.html.eex
|
@@ -1,48 +1,48 @@
|
1
|
- <%= if Adminable.PaginationView.show_pagination?(@total_pages) do %>
|
1
|
+ <%= if Adminable.AdminView.show_pagination?(@total_pages) do %>
|
2
2
|
<div class="rev-PaginationWrapper text-center">
|
3
3
|
<ul class="rev-Pagination" role="navigation" aria-label="Pagination">
|
4
|
- <%= unless Adminable.PaginationView.first_page?(@page_number) do %>
|
4
|
+ <%= unless Adminable.AdminView.first_page?(@page_number) do %>
|
5
5
|
<li class="rev-Pagination-arrow">
|
6
|
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, 1, @url) %>">
|
6
|
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, 1, @url) %>">
|
7
7
|
<span><i class="icon-angle-double-left"></i>First<span class="ShowForSR"> page</span></span>
|
8
8
|
</a>
|
9
9
|
</li>
|
10
10
|
<li class="rev-Pagination-arrow">
|
11
|
- <a href="<%= Adminable.PaginationView.make_previous_page_link(@conn, @page_number, @url) %>">
|
11
|
+ <a href="<%= Adminable.AdminView.make_previous_page_link(@conn, @page_number, @url) %>">
|
12
12
|
<span><i class="icon-angle-left"></i>Previous<span class="ShowForSR"> page</span></span>
|
13
13
|
</a>
|
14
14
|
</li>
|
15
15
|
<% end %>
|
16
16
|
|
17
17
|
<%= for page <- 1..@total_pages do %>
|
18
|
- <%= if Adminable.PaginationView.show_previous_ellipsis?(page, @page_number) do %>
|
18
|
+ <%= if Adminable.AdminView.show_previous_ellipsis?(page, @page_number) do %>
|
19
19
|
<li class="rev-Pagination-dots">
|
20
20
|
...
|
21
21
|
</li>
|
22
22
|
<% end %>
|
23
|
- <%= if Adminable.PaginationView.show_page_link?(page, @page_number) do %>
|
24
|
- <li class="rev-Pagination-number <%= Adminable.PaginationView.selected_page_class(page, @page_number)%>">
|
23
|
+ <%= if Adminable.AdminView.show_page_link?(page, @page_number) do %>
|
24
|
+ <li class="rev-Pagination-number <%= Adminable.AdminView.selected_page_class(page, @page_number)%>">
|
25
25
|
<%= if page == @page_number do %>
|
26
26
|
<span class="ShowForSR">You're on page </span><a><%= @page_number %></a>
|
27
27
|
<% else %>
|
28
|
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, page, @url) %>" aria-label="Page <%= page %>"><%= page %></a>
|
28
|
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, page, @url) %>" aria-label="Page <%= page %>"><%= page %></a>
|
29
29
|
<% end %>
|
30
30
|
</li>
|
31
31
|
<% end %>
|
32
|
- <%= if Adminable.PaginationView.show_next_ellipsis?(page, @page_number, @total_pages) do %>
|
32
|
+ <%= if Adminable.AdminView.show_next_ellipsis?(page, @page_number, @total_pages) do %>
|
33
33
|
<li class="rev-Pagination-dots">
|
34
34
|
...
|
35
35
|
</li>
|
36
36
|
<% end %>
|
37
37
|
<% end %>
|
38
|
- <%= unless Adminable.PaginationView.last_page?(@page_number, @total_pages) do %>
|
38
|
+ <%= unless Adminable.AdminView.last_page?(@page_number, @total_pages) do %>
|
39
39
|
<li class="rev-Pagination-arrow">
|
40
|
- <a href="<%= Adminable.PaginationView.make_next_page_link(@conn, @page_number, @url) %>">
|
40
|
+ <a href="<%= Adminable.AdminView.make_next_page_link(@conn, @page_number, @url) %>">
|
41
41
|
<span>Next<span class="ShowForSR"> page</span><i class="icon-angle-right"></i></span>
|
42
42
|
</a>
|
43
43
|
</li>
|
44
44
|
<li class="rev-Pagination-arrow">
|
45
|
- <a href="<%= Adminable.PaginationView.make_page_link(@conn, @total_pages, @url) %>">
|
45
|
+ <a href="<%= Adminable.AdminView.make_page_link(@conn, @total_pages, @url) %>">
|
46
46
|
<span>Last<span class="ShowForSR"> page</span><i class="icon-angle-double-right"></i></span>
|
47
47
|
</a>
|
48
48
|
</li>
|
changed
lib/adminable/templates/admin/dashboard.html.eex
|
@@ -1,11 +1,11 @@
|
1
|
- <%= row do %>
|
2
|
- <%= col do %>
|
1
|
+ <div class="rev-Row">
|
2
|
+ <div class="rev-Col">
|
3
3
|
<h1>Admin Dashboard</h1>
|
4
|
- <% end %>
|
5
|
- <% end %>
|
4
|
+ </div>
|
5
|
+ </div>
|
6
6
|
|
7
|
- <%= row do %>
|
8
|
- <%= col do %>
|
7
|
+ <div class="rev-Row">
|
8
|
+ <div class="rev-Col">
|
9
9
|
<div class="rev-TableContainer">
|
10
10
|
<table class="rev-Table">
|
11
11
|
<thead class="rev-Table-head">
|
|
@@ -24,5 +24,5 @@
|
24
24
|
</tbody>
|
25
25
|
</table>
|
26
26
|
</div>
|
27
|
- <% end %>
|
28
|
- <% end %>
|
27
|
+ </div>
|
28
|
+ </div>
|
changed
lib/adminable/templates/admin/edit.html.eex
|
@@ -1,25 +1,25 @@
|
1
|
- <%= row do %>
|
2
|
- <%= col class: "rev-Col--medium7 rev-Col--smallCentered" do %>
|
3
|
- <%= row do %>
|
4
|
- <%= col do %>
|
1
|
+ <div class="rev-Row">
|
2
|
+ <div class="rev-Col rev-Col--medium7 rev-Col--smallCentered" do %>
|
3
|
+ <div class="rev-Row">
|
4
|
+ <div class="rev-Col">
|
5
5
|
<h2 class="u-break-word">Edit <%= String.capitalize(@schema) %></h2>
|
6
|
- <% end %>
|
7
|
- <% end %>
|
8
|
- <%= form_for @changeset, Routes.admin_path(@conn, :update, @schema, @pk), [as: :data], fn f -> %>
|
9
|
- <%= row do %>
|
6
|
+ </div>
|
7
|
+ </div>
|
8
|
+ <%= form_for @changeset, Adminable.Router.Helpers.admin_path(@conn, :update, @schema, @pk), [as: :data], fn f -> %>
|
9
|
+ <div class="rev-Row">
|
10
10
|
<%= for field <- form_fields(@changeset) do %>
|
11
11
|
<%= field(f, @schema_module, field) %>
|
12
12
|
<% end %>
|
13
|
- <% end %>
|
13
|
+ </div>
|
14
14
|
|
15
|
- <%= row do %>
|
16
|
- <%= col do %>
|
15
|
+ <div class="rev-Row">
|
16
|
+ <div class="rev-Col">
|
17
17
|
<section class="u-noBorder-bottom u-flexAlignEnd">
|
18
18
|
<button class="rev-Button" type="submit">Edit</button>
|
19
19
|
</section>
|
20
|
- <% end %>
|
21
|
- <% end %>
|
20
|
+ </div>
|
21
|
+ </div>
|
22
22
|
|
23
23
|
<% end %>
|
24
|
- <% end %>
|
25
|
- <% end %>
|
24
|
+ </div>
|
25
|
+ </div>
|
changed
lib/adminable/templates/admin/index.html.eex
|
@@ -1,17 +1,17 @@
|
1
|
- <%= row do %>
|
2
|
- <%= col do %>
|
1
|
+ <div class="rev-Row">
|
2
|
+ <div class="rev-Col">
|
3
3
|
<h1><%= String.capitalize(@schema) %></h1>
|
4
|
- <% end %>
|
5
|
- <% end %>
|
4
|
+ </div>
|
5
|
+ </div>
|
6
6
|
|
7
|
- <%= row do %>
|
8
|
- <%= col do %>
|
9
|
- <%= link "New #{String.capitalize(@schema)}", to: Routes.admin_path(@conn, :new, @schema), class: button_class() %>
|
10
|
- <% end %>
|
11
|
- <% end %>
|
7
|
+ <div class="rev-Row">
|
8
|
+ <div class="rev-Col">
|
9
|
+ <%= link "New #{String.capitalize(@schema)}", to: Adminable.Router.Helpers.admin_path(@conn, :new, @schema), class: "rev-Button" %>
|
10
|
+ </div>
|
11
|
+ </div>
|
12
12
|
|
13
|
- <%= row do %>
|
14
|
- <%= col do %>
|
13
|
+ <div class="rev-Row">
|
14
|
+ <div class="rev-Col">
|
15
15
|
<div class="rev-TableContainer">
|
16
16
|
<table class="rev-Table">
|
17
17
|
<thead class="rev-Table-head">
|
|
@@ -29,7 +29,7 @@
|
29
29
|
<td class="rev-Table-Data"><%= Map.get(schema, field) %></td>
|
30
30
|
<% end %>
|
31
31
|
<td>
|
32
|
- <%= link "Edit", to: Routes.admin_path(@conn, :edit, @schema, schema.id), class: button_class(secondary: true) %>
|
32
|
+ <%= link "Edit", to: Adminable.Router.Helpers.admin_path(@conn, :edit, @schema, schema.id), class: "rev-Button rev-Button--secondary" %>
|
33
33
|
</td>
|
34
34
|
<tr>
|
35
35
|
<% end %>
|
|
@@ -43,7 +43,7 @@
|
43
43
|
page_size: @page_size,
|
44
44
|
total_entries: @total_entries,
|
45
45
|
total_pages: @total_pages,
|
46
|
- url: Routes.admin_path(@conn, :index, @schema)
|
46
|
+ url: Adminable.Router.Helpers.admin_path(@conn, :index, @schema)
|
47
47
|
%>
|
48
|
- <% end %>
|
49
|
- <% end %>
|
48
|
+ </div>
|
49
|
+ </div>
|
changed
lib/adminable/templates/admin/new.html.eex
|
@@ -1,25 +1,25 @@
|
1
|
- <%= row do %>
|
2
|
- <%= col class: "rev-Col--medium7 rev-Col--smallCentered" do %>
|
3
|
- <%= row do %>
|
4
|
- <%= col do %>
|
1
|
+ <div class="rev-Row">
|
2
|
+ <div class="rev-Col rev-Col--medium7 rev-Col--smallCentered">
|
3
|
+ <div class="rev-Row">
|
4
|
+ <div class="rev-Col">
|
5
5
|
<h2 class="u-break-word">New <%= String.capitalize(@schema) %></h2>
|
6
|
- <% end %>
|
7
|
- <% end %>
|
8
|
- <%= form_for @changeset, Routes.admin_path(@conn, :create, @schema), [as: :data], fn f -> %>
|
9
|
- <%= row do %>
|
6
|
+ </div>
|
7
|
+ </div>
|
8
|
+ <%= form_for @changeset, Adminable.Router.Helpers.admin_path(@conn, :create, @schema), [as: :data], fn f -> %>
|
9
|
+ <div class="rev-Row">
|
10
10
|
<%= for field <- form_fields(@changeset) do %>
|
11
11
|
<%= field(f, @schema_module, field) %>
|
12
12
|
<% end %>
|
13
|
- <% end %>
|
13
|
+ </div>
|
14
14
|
|
15
|
- <%= row do %>
|
16
|
- <%= col do %>
|
15
|
+ <div class="rev-Row">
|
16
|
+ <div class="rev-Col">
|
17
17
|
<section class="u-noBorder-bottom u-flexAlignEnd">
|
18
18
|
<button class="rev-Button" type="submit">Create</button>
|
19
19
|
</section>
|
20
|
- <% end %>
|
21
|
- <% end %>
|
20
|
+ </div>
|
21
|
+ </div>
|
22
22
|
|
23
23
|
<% end %>
|
24
|
- <% end %>
|
25
|
- <% end %>
|
24
|
+ </div>
|
25
|
+ </div>
|
changed
lib/adminable/views/admin_view.ex
|
@@ -5,22 +5,5 @@ defmodule Adminable.AdminView do
|
5
5
|
root: "lib/adminable/templates",
|
6
6
|
namespace: Adminable
|
7
7
|
|
8
|
- # Use all HTML functionality (forms, tags, etc)
|
9
|
- use Phoenix.HTML
|
10
|
-
|
11
|
- alias Adminable.Router.Helpers, as: Routes
|
12
|
- import Harmonium
|
13
|
-
|
14
|
- def index_fields(schema_module) do
|
15
|
- schema_module.fields()
|
16
|
- end
|
17
|
-
|
18
|
- def form_fields(changeset) do
|
19
|
- schema = changeset.data
|
20
|
-
|
21
|
- fields = schema.__struct__.fields() -- [:inserted_at, :updated_at]
|
22
|
- fields -- schema.__struct__.__schema__(:primary_key)
|
23
|
- end
|
24
|
-
|
25
|
- defdelegate field(form, schema_module, field, opts \\ []), to: Adminable.Field
|
8
|
+ use Adminable.ViewHelpers
|
26
9
|
end
|
changed
lib/adminable/views/field.ex
|
@@ -12,7 +12,7 @@ defmodule Adminable.Field do
|
12
12
|
defp field_html(form, field, :boolean, opts) do
|
13
13
|
~E"""
|
14
14
|
<%= col do %>
|
15
|
- <%= single_checkbox(form, field, Keyword.merge([label: String.capitalize(to_string(field))], opts)) %>
|
15
|
+ <%= single_checkbox(form, field, Keyword.merge([label: Phoenix.Naming.humanize(field)], opts)) %>
|
16
16
|
<% end %>
|
17
17
|
"""
|
18
18
|
end
|
|
@@ -23,7 +23,7 @@ defmodule Adminable.Field do
|
23
23
|
<%= number_input_stack(
|
24
24
|
form,
|
25
25
|
field,
|
26
|
- label: String.capitalize(to_string(field)),
|
26
|
+ label: Phoenix.Naming.humanize(field),
|
27
27
|
input: Keyword.merge([], opts))
|
28
28
|
%>
|
29
29
|
<% end %>
|
|
@@ -36,8 +36,8 @@ defmodule Adminable.Field do
|
36
36
|
<%= text_input_stack(
|
37
37
|
form,
|
38
38
|
field,
|
39
|
- label: String.capitalize(to_string(field)),
|
40
|
- input: Keyword.merge([placeholder: String.capitalize(to_string(field))], opts))
|
39
|
+ label: Phoenix.Naming.humanize(field),
|
40
|
+ input: Keyword.merge([placeholder: Phoenix.Naming.humanize(field)], opts))
|
41
41
|
%>
|
42
42
|
<% end %>
|
43
43
|
"""
|
removed
lib/adminable/views/pagination_view.ex
|
@@ -1,65 +0,0 @@
|
1
|
- defmodule Adminable.PaginationView do
|
2
|
- @moduledoc false
|
3
|
-
|
4
|
- @page_links_to_show 2
|
5
|
-
|
6
|
- def make_next_page_link(conn, current_page, url) do
|
7
|
- make_page_link(conn, current_page + 1, url)
|
8
|
- end
|
9
|
-
|
10
|
- def make_previous_page_link(conn, current_page, url) do
|
11
|
- make_page_link(conn, current_page - 1, url)
|
12
|
- end
|
13
|
-
|
14
|
- def make_page_link(conn, page, url) do
|
15
|
- query_params = conn.query_params
|
16
|
-
|
17
|
- query_params = Map.put(query_params, "page", page)
|
18
|
-
|
19
|
- uri = URI.parse(url)
|
20
|
-
|
21
|
- query_params =
|
22
|
- if is_nil(uri.query) do
|
23
|
- query_params
|
24
|
- else
|
25
|
- URI.decode_query(uri.query, query_params)
|
26
|
- end
|
27
|
-
|
28
|
- uri = %{uri | query: Plug.Conn.Query.encode(query_params)}
|
29
|
-
|
30
|
- URI.to_string(uri)
|
31
|
- end
|
32
|
-
|
33
|
- def first_page?(1), do: true
|
34
|
- def first_page?(_), do: false
|
35
|
-
|
36
|
- def last_page?(page_number, total_pages) when page_number == total_pages, do: true
|
37
|
- def last_page?(_, _), do: false
|
38
|
-
|
39
|
- def show_pagination?(1), do: false
|
40
|
- def show_pagination?(_), do: true
|
41
|
-
|
42
|
- def selected_page_class(page_number, current_page) when page_number == current_page do
|
43
|
- "rev-Pagination-number--selected"
|
44
|
- end
|
45
|
-
|
46
|
- def selected_page_class(_, _) do
|
47
|
- ""
|
48
|
- end
|
49
|
-
|
50
|
- def show_previous_ellipsis?(1, _) do
|
51
|
- false
|
52
|
- end
|
53
|
-
|
54
|
- def show_previous_ellipsis?(page, page_number) do
|
55
|
- page == page_number - @page_links_to_show
|
56
|
- end
|
57
|
-
|
58
|
- def show_next_ellipsis?(page, page_number, total_pages) do
|
59
|
- page == page_number + @page_links_to_show and page != total_pages
|
60
|
- end
|
61
|
-
|
62
|
- def show_page_link?(page, page_number) do
|
63
|
- page >= page_number - @page_links_to_show and page <= page_number + @page_links_to_show
|
64
|
- end
|
65
|
- end
|
added
lib/adminable/views/view_helpers.ex
|
@@ -0,0 +1,83 @@
|
1
|
+ defmodule Adminable.ViewHelpers do
|
2
|
+ @moduledoc false
|
3
|
+
|
4
|
+ defmacro __using__(_opts) do
|
5
|
+ quote do
|
6
|
+ use Phoenix.HTML
|
7
|
+ @page_links_to_show 2
|
8
|
+
|
9
|
+ def index_fields(schema_module) do
|
10
|
+ schema_module.fields()
|
11
|
+ end
|
12
|
+
|
13
|
+ def form_fields(changeset) do
|
14
|
+ schema = changeset.data
|
15
|
+
|
16
|
+ fields = schema.__struct__.fields() -- [:inserted_at, :updated_at]
|
17
|
+ fields -- schema.__struct__.__schema__(:primary_key)
|
18
|
+ end
|
19
|
+
|
20
|
+ defdelegate field(form, schema_module, field, opts \\ []), to: Adminable.Field
|
21
|
+
|
22
|
+ def make_next_page_link(conn, current_page, url) do
|
23
|
+ make_page_link(conn, current_page + 1, url)
|
24
|
+ end
|
25
|
+
|
26
|
+ def make_previous_page_link(conn, current_page, url) do
|
27
|
+ make_page_link(conn, current_page - 1, url)
|
28
|
+ end
|
29
|
+
|
30
|
+ def make_page_link(conn, page, url) do
|
31
|
+ query_params = conn.query_params
|
32
|
+
|
33
|
+ query_params = Map.put(query_params, "page", page)
|
34
|
+
|
35
|
+ uri = URI.parse(url)
|
36
|
+
|
37
|
+ query_params =
|
38
|
+ if is_nil(uri.query) do
|
39
|
+ query_params
|
40
|
+ else
|
41
|
+ URI.decode_query(uri.query, query_params)
|
42
|
+ end
|
43
|
+
|
44
|
+ uri = %{uri | query: Plug.Conn.Query.encode(query_params)}
|
45
|
+
|
46
|
+ URI.to_string(uri)
|
47
|
+ end
|
48
|
+
|
49
|
+ def first_page?(1), do: true
|
50
|
+ def first_page?(_), do: false
|
51
|
+
|
52
|
+ def last_page?(page_number, total_pages) when page_number == total_pages, do: true
|
53
|
+ def last_page?(_, _), do: false
|
54
|
+
|
55
|
+ def show_pagination?(1), do: false
|
56
|
+ def show_pagination?(_), do: true
|
57
|
+
|
58
|
+ def selected_page_class(page_number, current_page) when page_number == current_page do
|
59
|
+ "rev-Pagination-number--selected"
|
60
|
+ end
|
61
|
+
|
62
|
+ def selected_page_class(_, _) do
|
63
|
+ ""
|
64
|
+ end
|
65
|
+
|
66
|
+ def show_previous_ellipsis?(1, _) do
|
67
|
+ false
|
68
|
+ end
|
69
|
+
|
70
|
+ def show_previous_ellipsis?(page, page_number) do
|
71
|
+ page == page_number - @page_links_to_show
|
72
|
+ end
|
73
|
+
|
74
|
+ def show_next_ellipsis?(page, page_number, total_pages) do
|
75
|
+ page == page_number + @page_links_to_show and page != total_pages
|
76
|
+ end
|
77
|
+
|
78
|
+ def show_page_link?(page, page_number) do
|
79
|
+ page >= page_number - @page_links_to_show and page <= page_number + @page_links_to_show
|
80
|
+ end
|
81
|
+ end
|
82
|
+ end
|
83
|
+ end
|
added
lib/mix/tasks/adminable.gen.view.ex
|
@@ -0,0 +1,23 @@
|
1
|
+ defmodule Mix.Tasks.Adminable.Gen.View do
|
2
|
+ @shortdoc "Generates views and templates"
|
3
|
+
|
4
|
+ @moduledoc """
|
5
|
+ Generates views and templates so that they can be modifed.
|
6
|
+ mix adminable.gen.view my_web_module
|
7
|
+
|
8
|
+ ## Arguments
|
9
|
+ * `my_web_module` - web_module to use for path and module names
|
10
|
+ """
|
11
|
+ use Mix.Task
|
12
|
+
|
13
|
+ @impl true
|
14
|
+ def run([web_module_string]) do
|
15
|
+ web_module = Module.concat([web_module_string])
|
16
|
+ Adminable.Exporter.export(web_module)
|
17
|
+ end
|
18
|
+
|
19
|
+ def run(_) do
|
20
|
+ Mix.Shell.IO.error("Invalid args. Usage mix adminable.gen.view my_web_module")
|
21
|
+ exit({:shutdown, 1})
|
22
|
+ end
|
23
|
+ end
|
changed
mix.exs
|
@@ -4,7 +4,7 @@ defmodule Adminable.MixProject do
|
4
4
|
def project do
|
5
5
|
[
|
6
6
|
app: :adminable,
|
7
|
- version: "0.2.0",
|
7
|
+ version: "0.3.0",
|
8
8
|
elixir: "~> 1.8",
|
9
9
|
start_permanent: Mix.env() == :prod,
|
10
10
|
deps: deps(),
|