madmin 1.0.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +29 -1
- data/app/controllers/madmin/base_controller.rb +0 -5
- data/app/controllers/madmin/resource_controller.rb +23 -2
- data/app/helpers/madmin/application_helper.rb +4 -0
- data/app/helpers/madmin/nav_helper.rb +30 -0
- data/app/helpers/madmin/sort_helper.rb +32 -0
- data/app/views/layouts/madmin/application.html.erb +5 -5
- data/app/views/madmin/application/_form.html.erb +6 -8
- data/app/views/madmin/application/_javascript.html.erb +73 -7
- data/app/views/madmin/application/_navigation.html.erb +31 -5
- data/app/views/madmin/application/edit.html.erb +5 -1
- data/app/views/madmin/application/index.html.erb +34 -22
- data/app/views/madmin/application/new.html.erb +5 -1
- data/app/views/madmin/application/show.html.erb +24 -17
- data/app/views/madmin/fields/attachment/_form.html.erb +3 -1
- data/app/views/madmin/fields/attachment/_show.html.erb +7 -1
- data/app/views/madmin/fields/attachments/_form.html.erb +3 -1
- data/app/views/madmin/fields/attachments/_show.html.erb +7 -3
- data/app/views/madmin/fields/belongs_to/_form.html.erb +4 -2
- data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
- data/app/views/madmin/fields/boolean/_form.html.erb +3 -1
- data/app/views/madmin/fields/date/_form.html.erb +3 -1
- data/app/views/madmin/fields/date_time/_form.html.erb +3 -1
- data/app/views/madmin/fields/decimal/_form.html.erb +3 -1
- data/app/views/madmin/fields/enum/_form.html.erb +4 -2
- data/app/views/madmin/fields/float/_form.html.erb +3 -1
- data/app/views/madmin/fields/has_many/_form.html.erb +4 -2
- data/app/views/madmin/fields/has_many/_show.html.erb +1 -1
- data/app/views/madmin/fields/has_one/_form.html.erb +3 -2
- data/app/views/madmin/fields/integer/_form.html.erb +3 -1
- data/app/views/madmin/fields/json/_form.html.erb +3 -1
- data/app/views/madmin/fields/nested_has_many/_fields.html.erb +18 -0
- data/app/views/madmin/fields/nested_has_many/_form.html.erb +32 -0
- data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -0
- data/app/views/madmin/fields/nested_has_many/_show.html.erb +5 -0
- data/app/views/madmin/fields/password/_form.html.erb +4 -0
- data/app/views/madmin/fields/password/_index.html.erb +1 -0
- data/app/views/madmin/fields/password/_show.html.erb +1 -0
- data/app/views/madmin/fields/polymorphic/_form.html.erb +3 -1
- data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
- data/app/views/madmin/fields/rich_text/_form.html.erb +3 -1
- data/app/views/madmin/fields/string/_form.html.erb +3 -1
- data/app/views/madmin/fields/text/_form.html.erb +3 -1
- data/app/views/madmin/fields/time/_form.html.erb +3 -1
- data/app/views/madmin/shared/_label.html.erb +4 -0
- data/lib/generators/madmin/field/field_generator.rb +31 -0
- data/lib/generators/madmin/field/templates/_form.html.erb +2 -0
- data/lib/generators/madmin/field/templates/_index.html.erb +1 -0
- data/lib/generators/madmin/field/templates/_show.html.erb +1 -0
- data/lib/generators/madmin/field/templates/field.rb.tt +26 -0
- data/lib/generators/madmin/install/install_generator.rb +6 -1
- data/lib/generators/madmin/install/templates/routes.rb.tt +3 -0
- data/lib/generators/madmin/resource/resource_generator.rb +15 -4
- data/lib/generators/madmin/resource/templates/controller.rb.tt +6 -0
- data/lib/generators/madmin/resource/templates/resource.rb.tt +14 -0
- data/lib/generators/madmin/views/javascript_generator.rb +15 -0
- data/lib/generators/madmin/views/views_generator.rb +6 -5
- data/lib/madmin/engine.rb +1 -1
- data/lib/madmin/field.rb +4 -0
- data/lib/madmin/fields/belongs_to.rb +9 -5
- data/lib/madmin/fields/has_many.rb +10 -5
- data/lib/madmin/fields/nested_has_many.rb +40 -0
- data/lib/madmin/fields/password.rb +6 -0
- data/lib/madmin/fields/string.rb +3 -0
- data/lib/madmin/fields/text.rb +3 -0
- data/lib/madmin/generator_helpers.rb +22 -4
- data/lib/madmin/resource.rb +53 -19
- data/lib/madmin/search.rb +60 -0
- data/lib/madmin/version.rb +1 -1
- data/lib/madmin.rb +30 -14
- metadata +25 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f3bd8e986e4859620b06401c531dc24ca84bb02e4e2284a34918b5a088c126c
|
4
|
+
data.tar.gz: 9bf59b4f93849feda832005caa748e02b4227ea2552cd6e94264d3b7d170f5a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3181e8f05aad7af36b905a4a04ffb2ddd63419b347e699b0b9ea6d8d2fb9a880f12ebbd7b12d05770e02dc7508e4789a1cb8250b11b6eed26878b6ef71d7fc1b
|
7
|
+
data.tar.gz: '0019a725b02cde9e007190917381da718a139662d1d9094a0e49ccc69b799437865a4170658b99492947ce1d6d2ae04f71dde97886212a8dd728c3a9aa2275f3'
|
data/README.md
CHANGED
@@ -7,9 +7,12 @@
|
|
7
7
|
Why another Ruby on Rails admin? We wanted an admin that was:
|
8
8
|
|
9
9
|
* Familiar and customizable like Rails scaffolds (less DSL)
|
10
|
-
* Supports all the Rails features out of the box (ActionText, ActionMailbox, etc)
|
10
|
+
* Supports all the Rails features out of the box (ActionText, ActionMailbox, has_secure_password, etc)
|
11
11
|
* Stimulus / Turbolinks / Hotwire ready
|
12
12
|
|
13
|
+

|
14
|
+
_We're still working on the design!_
|
15
|
+
|
13
16
|
## Installation
|
14
17
|
Add `madmin` to your application's Gemfile:
|
15
18
|
|
@@ -76,6 +79,31 @@ rails generate madmin:views:index Book
|
|
76
79
|
# -> app/views/madmin/books/index.html.erb
|
77
80
|
```
|
78
81
|
|
82
|
+
## Custom Fields
|
83
|
+
|
84
|
+
You can generate a custom field with:
|
85
|
+
|
86
|
+
```bash
|
87
|
+
rails g madmin:field Custom
|
88
|
+
```
|
89
|
+
|
90
|
+
This will create a `CustomField` class in `app/madmin/fields/custom_field.rb`
|
91
|
+
And the related views:
|
92
|
+
|
93
|
+
```bash
|
94
|
+
# -> app/views/madmin/fields/custom_field/_form.html.erb
|
95
|
+
# -> app/views/madmin/fields/custom_field/_index.html.erb
|
96
|
+
# -> app/views/madmin/fields/custom_field/_show.html.erb
|
97
|
+
```
|
98
|
+
|
99
|
+
You can then use this field on our resource:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class PostResource < Madmin::Resource
|
103
|
+
attribute :title, field: CustomField
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
79
107
|
## Authentication
|
80
108
|
|
81
109
|
You can use a couple of strategies to authenticate users who are trying to
|
@@ -1,9 +1,24 @@
|
|
1
1
|
module Madmin
|
2
2
|
class ResourceController < ApplicationController
|
3
|
+
include SortHelper
|
4
|
+
|
3
5
|
before_action :set_record, except: [:index, :new, :create]
|
4
6
|
|
7
|
+
# Assign current_user for paper_trail gem
|
8
|
+
before_action :set_paper_trail_whodunnit, if: -> { respond_to?(:set_paper_trail_whodunnit, true) }
|
9
|
+
|
5
10
|
def index
|
6
11
|
@pagy, @records = pagy(scoped_resources)
|
12
|
+
|
13
|
+
respond_to do |format|
|
14
|
+
format.html
|
15
|
+
format.json {
|
16
|
+
render json: @records.map { |r| {name: @resource.display_name(r), id: r.id} }
|
17
|
+
}
|
18
|
+
end
|
19
|
+
rescue Pagy::OverflowError
|
20
|
+
params[:page] = 1
|
21
|
+
retry
|
7
22
|
end
|
8
23
|
|
9
24
|
def show
|
@@ -41,7 +56,7 @@ module Madmin
|
|
41
56
|
private
|
42
57
|
|
43
58
|
def set_record
|
44
|
-
@record = resource.
|
59
|
+
@record = resource.model_find(params[:id])
|
45
60
|
end
|
46
61
|
|
47
62
|
def resource
|
@@ -54,7 +69,9 @@ module Madmin
|
|
54
69
|
end
|
55
70
|
|
56
71
|
def scoped_resources
|
57
|
-
resource.model.send(valid_scope)
|
72
|
+
resources = resource.model.send(valid_scope)
|
73
|
+
resources = Madmin::Search.new(resources, resource, search_term).run
|
74
|
+
resources.reorder(sort_column => sort_direction)
|
58
75
|
end
|
59
76
|
|
60
77
|
def valid_scope
|
@@ -77,5 +94,9 @@ module Madmin
|
|
77
94
|
raise "Unrecognised param data: #{data.inspect}"
|
78
95
|
end
|
79
96
|
end
|
97
|
+
|
98
|
+
def search_term
|
99
|
+
@search_term ||= params[:q].to_s.strip
|
100
|
+
end
|
80
101
|
end
|
81
102
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Madmin::NavHelper
|
2
|
+
def nav_link_to(name = nil, options = {}, html_options = {}, &block)
|
3
|
+
if block
|
4
|
+
html_options = options
|
5
|
+
options = name
|
6
|
+
name = block
|
7
|
+
end
|
8
|
+
|
9
|
+
url = url_for(options)
|
10
|
+
starts_with = html_options.delete(:starts_with)
|
11
|
+
html_options[:class] = Array.wrap(html_options[:class])
|
12
|
+
active_class = html_options.delete(:active_class) || "active"
|
13
|
+
inactive_class = html_options.delete(:inactive_class) || ""
|
14
|
+
|
15
|
+
active = if (paths = Array.wrap(starts_with)) && paths.present?
|
16
|
+
paths.any? { |path| request.path.start_with?(path) }
|
17
|
+
else
|
18
|
+
request.path == url
|
19
|
+
end
|
20
|
+
|
21
|
+
classes = active ? active_class : inactive_class
|
22
|
+
html_options[:class] << classes unless classes.empty?
|
23
|
+
|
24
|
+
html_options.except!(:class) if html_options[:class].empty?
|
25
|
+
|
26
|
+
return link_to url, html_options, &block if block
|
27
|
+
|
28
|
+
link_to name, url, html_options
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Madmin
|
2
|
+
module SortHelper
|
3
|
+
def sortable(column, title, options = {})
|
4
|
+
matching_column = (column.to_s == sort_column)
|
5
|
+
direction = sort_direction == "asc" ? "desc" : "asc"
|
6
|
+
|
7
|
+
link_to request.params.merge(sort: column, direction: direction), options do
|
8
|
+
concat title
|
9
|
+
if matching_column
|
10
|
+
concat " "
|
11
|
+
concat tag.i(sort_direction == "asc" ? "▲" : "▼")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def sort_column
|
17
|
+
resource.sortable_columns.include?(params[:sort]) ? params[:sort] : default_sort_column
|
18
|
+
end
|
19
|
+
|
20
|
+
def sort_direction
|
21
|
+
["asc", "desc"].include?(params[:direction]) ? params[:direction] : default_sort_direction
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_sort_column
|
25
|
+
resource.try(:default_sort_column) || (["created_at", "id", "uuid"] & resource.model.column_names).first
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_sort_direction
|
29
|
+
resource.try(:default_sort_direction) || "desc"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -7,19 +7,19 @@
|
|
7
7
|
<title>
|
8
8
|
Madmin: <%= Rails.application.class %>
|
9
9
|
</title>
|
10
|
-
<link href="https://unpkg.com/tailwindcss@^2.0/dist/tailwind.min.css" rel="stylesheet" />
|
11
10
|
<link href="https://unpkg.com/@tailwindcss/forms/dist/forms.min.css" rel="stylesheet" />
|
11
|
+
<link href="https://unpkg.com/tailwindcss@^2.0/dist/tailwind.min.css" rel="stylesheet" />
|
12
12
|
<link href="https://unpkg.com/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet" />
|
13
13
|
<%= csrf_meta_tags %>
|
14
14
|
|
15
15
|
<%= render "javascript" %>
|
16
16
|
</head>
|
17
|
-
<body class="
|
18
|
-
<div class="flex w-full
|
19
|
-
<div id="sidebar" class="w-64 flex-shrink-0">
|
17
|
+
<body class="min-h-screen">
|
18
|
+
<div class="md:flex w-full min-h-screen">
|
19
|
+
<div id="sidebar" class="md:w-64 p-4 flex-shrink-0 border-r">
|
20
20
|
<%= render "navigation" -%>
|
21
21
|
</div>
|
22
|
-
<main class="
|
22
|
+
<main class="flex-grow p-4" role="main">
|
23
23
|
<%#= render "flashes" -%>
|
24
24
|
<%= yield %>
|
25
25
|
</main>
|
@@ -9,15 +9,13 @@
|
|
9
9
|
</div>
|
10
10
|
<% end %>
|
11
11
|
|
12
|
-
<% resource.attributes.each do |attribute| %>
|
13
|
-
<% next if attribute
|
14
|
-
<% next unless attribute
|
15
|
-
<% next unless attribute
|
12
|
+
<% resource.attributes.values.each do |attribute| %>
|
13
|
+
<% next if attribute.field.nil? %>
|
14
|
+
<% next unless attribute.field.visible?(action_name) %>
|
15
|
+
<% next unless attribute.field.visible?(:form) %>
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
<div class="mb-4 flex">
|
20
|
-
<%= render partial: field.to_partial_path("form"), locals: { field: field, record: record, form: form, resource: resource } %>
|
17
|
+
<div class="mb-4 md:flex">
|
18
|
+
<%= render partial: attribute.field.to_partial_path("form"), locals: { field: attribute.field, record: record, form: form, resource: resource } %>
|
21
19
|
</div>
|
22
20
|
<% end %>
|
23
21
|
|
@@ -1,24 +1,90 @@
|
|
1
|
-
<%= stylesheet_link_tag "https://
|
2
|
-
<%= stylesheet_link_tag "https://
|
3
|
-
<%= stylesheet_link_tag "https://
|
1
|
+
<%= stylesheet_link_tag "https://unpkg.com/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
|
2
|
+
<%= stylesheet_link_tag "https://unpkg.com/trix/dist/trix.css", "data-turbo-track": "reload" %>
|
3
|
+
<%= stylesheet_link_tag "https://unpkg.com/tom-select/dist/css/tom-select.min.css", "data-turbo-track": "reload" %>
|
4
4
|
|
5
5
|
<script type="module">
|
6
|
-
import { Application } from 'https://cdn.skypack.dev/stimulus'
|
6
|
+
import { Application, Controller } from 'https://cdn.skypack.dev/stimulus'
|
7
7
|
const application = Application.start()
|
8
8
|
|
9
|
+
import { Dropdown } from "https://cdn.skypack.dev/tailwindcss-stimulus-components"
|
10
|
+
application.register("dropdown", Dropdown)
|
11
|
+
|
9
12
|
import stimulusFlatpickr from 'https://cdn.skypack.dev/stimulus-flatpickr'
|
10
13
|
application.register("flatpickr", stimulusFlatpickr)
|
11
14
|
|
12
|
-
import
|
13
|
-
application.register("slimselect", stimulusSlimselect)
|
15
|
+
import TomSelect from 'https://cdn.skypack.dev/tom-select'
|
14
16
|
|
15
17
|
import Rails from 'https://cdn.skypack.dev/@rails/ujs@<%= npm_rails_version %>'
|
16
18
|
import * as ActiveStorage from 'https://cdn.skypack.dev/@rails/activestorage@<%= npm_rails_version %>'
|
17
19
|
import 'https://cdn.skypack.dev/trix'
|
18
20
|
import 'https://cdn.skypack.dev/@rails/actiontext@<%= npm_rails_version %>'
|
19
21
|
|
20
|
-
Rails.start()
|
22
|
+
if (!window._rails_loaded) { Rails.start() }
|
21
23
|
ActiveStorage.start()
|
22
24
|
|
23
25
|
import * as Turbo from "https://cdn.skypack.dev/@hotwired/turbo"
|
26
|
+
|
27
|
+
(() => {
|
28
|
+
application.register('select', class extends Controller {
|
29
|
+
static values = {
|
30
|
+
options: Object,
|
31
|
+
url: String
|
32
|
+
}
|
33
|
+
|
34
|
+
connect() {
|
35
|
+
this.select = new TomSelect(this.element, {
|
36
|
+
plugins: ['remove_button'],
|
37
|
+
valueField: 'id',
|
38
|
+
labelField: 'name',
|
39
|
+
searchField: 'name',
|
40
|
+
load: (search, callback) => {
|
41
|
+
fetch(this.urlValue)
|
42
|
+
.then(response => response.json())
|
43
|
+
.then(json => {
|
44
|
+
callback(json);
|
45
|
+
}).catch(() => {
|
46
|
+
callback();
|
47
|
+
});
|
48
|
+
}
|
49
|
+
})
|
50
|
+
}
|
51
|
+
|
52
|
+
disconnect() {
|
53
|
+
this.select.destroy()
|
54
|
+
}
|
55
|
+
})
|
56
|
+
|
57
|
+
application.register('nested-form', class extends Controller {
|
58
|
+
static get targets() {
|
59
|
+
return [ "links", "template" ]
|
60
|
+
}
|
61
|
+
|
62
|
+
connect() {
|
63
|
+
this.wrapperClass = this.data.get("wrapperClass") || "nested-fields"
|
64
|
+
}
|
65
|
+
|
66
|
+
add_association(event) {
|
67
|
+
event.preventDefault()
|
68
|
+
|
69
|
+
var content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime())
|
70
|
+
this.linksTarget.insertAdjacentHTML('beforebegin', content)
|
71
|
+
}
|
72
|
+
|
73
|
+
remove_association(event) {
|
74
|
+
event.preventDefault()
|
75
|
+
|
76
|
+
let wrapper = event.target.closest("." + this.wrapperClass)
|
77
|
+
|
78
|
+
// New records are simply removed from the page
|
79
|
+
if (wrapper.dataset.newRecord == "true") {
|
80
|
+
wrapper.remove()
|
81
|
+
|
82
|
+
// Existing records are hidden and flagged for deletion
|
83
|
+
} else {
|
84
|
+
wrapper.querySelector("input[name*='_destroy']").value = 1
|
85
|
+
wrapper.style.display = 'none'
|
86
|
+
}
|
87
|
+
}
|
88
|
+
})
|
89
|
+
})()
|
24
90
|
</script>
|
@@ -1,6 +1,32 @@
|
|
1
|
-
<div class="text-sm">
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<div class="flex flex-col h-full text-sm" data-controller="dropdown">
|
2
|
+
<div class="flex md:block justify-between items-center">
|
3
|
+
<div class="flex md:block items-center">
|
4
|
+
<h1 class="mr-2 md:p-2 text-xl font-semibold">Madmin</h1>
|
5
|
+
<% if main_app.respond_to?(:root_url) %>
|
6
|
+
<%= link_to main_app.root_url, class: "block p-2 rounded hover:bg-gray-200", data: { turbo: false } do %>
|
7
|
+
← Back <span class="hidden md:inline">to App</span>
|
8
|
+
<% end %>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div class="-mr-2 flex items-center md:hidden">
|
13
|
+
<button data-action="click->dropdown#toggle touch->dropdown#toggle click@window->dropdown#hide touch@window#dropdown->hide" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:bg-gray-200 focus:outline-none focus:ring-2 focus-ring-inset focus:ring-white" id="main-menu" aria-haspopup="true">
|
14
|
+
<span class="sr-only">Open main menu</span>
|
15
|
+
<!-- Heroicon name: outline/menu -->
|
16
|
+
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
17
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
18
|
+
</svg>
|
19
|
+
</button>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<div class="hidden md:flex flex-col flex-grow justify-between" data-dropdown-target="menu">
|
24
|
+
<% Madmin.resources.each do |resource| %>
|
25
|
+
<%= nav_link_to resource.friendly_name.pluralize, resource.index_path, class: "block p-2 rounded hover:bg-gray-100", starts_with: resource.index_path, active_class: "font-bold text-black" %>
|
26
|
+
<% end %>
|
27
|
+
|
28
|
+
<div class="mt-auto">
|
29
|
+
<%= link_to "View Madmin on GitHub", "https://github.com/excid3/madmin", target: :_blank, class: "block p-2 rounded text-gray-500 hover:bg-gray-100" %>
|
30
|
+
</div>
|
31
|
+
</div>
|
6
32
|
</div>
|
@@ -1,3 +1,7 @@
|
|
1
|
-
<h1
|
1
|
+
<h1 class="text-xl mb-4">
|
2
|
+
<%= link_to resource.friendly_name.pluralize, resource.index_path, class: "text-indigo-500" %>
|
3
|
+
/
|
4
|
+
<strong>Edit <%= link_to resource.display_name(@record), resource.show_path(@record), class: "text-indigo-500" %></strong>
|
5
|
+
</h1>
|
2
6
|
|
3
7
|
<%= render partial: "form", locals: { record: @record, resource: resource } %>
|
@@ -1,44 +1,56 @@
|
|
1
|
-
<div class="flex justify-between">
|
2
|
-
<h1><%= resource.friendly_name.pluralize %></h1>
|
3
|
-
|
1
|
+
<div class="md:flex justify-between items-center space-y-4 md:space-y-0">
|
2
|
+
<h1 class="text-xl font-semibold"><%= resource.friendly_name.pluralize %></h1>
|
3
|
+
|
4
|
+
<div class="flex-grow flex md:justify-end gap-4">
|
5
|
+
<form class="flex items-center gap-2 relative">
|
6
|
+
<%= hidden_field_tag :page, params[:page], value: 1, class: "hidden" %>
|
7
|
+
<%= search_field_tag :q, params[:q], placeholder: "Search", class: "rounded-full px-4 focus:bg-white focus:border-indigo-500" %>
|
8
|
+
<%= link_to clear_search_params, class: "absolute top-1/2 right-3 text-gray-500 bg-white transform -translate-y-1/2" do %>
|
9
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
10
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
11
|
+
</svg>
|
12
|
+
<% end %>
|
13
|
+
</form>
|
14
|
+
|
15
|
+
<%= link_to resource.new_path, class: "bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow" do %>
|
16
|
+
New <span class="hidden md:inline"><%= resource.friendly_name %></span>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
4
19
|
</div>
|
5
20
|
|
6
|
-
<div>
|
21
|
+
<div class="mb-4">
|
7
22
|
<% if resource.scopes.any? %>
|
8
|
-
<%= link_to "All", resource.index_path %>
|
23
|
+
<%= link_to "All", resource.index_path, class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope].blank?}) %>
|
9
24
|
<% end %>
|
10
25
|
|
11
26
|
<% resource.scopes.each do |scope| %>
|
12
|
-
<%= link_to scope.to_s.humanize, resource.index_path(scope: scope) %>
|
27
|
+
<%= link_to scope.to_s.humanize, resource.index_path(scope: scope), class: class_names("p-2 rounded", {"bg-gray-100" => params[:scope] == scope.to_s}) %>
|
13
28
|
<% end %>
|
14
29
|
</div>
|
15
30
|
|
16
|
-
<table class="
|
31
|
+
<table class="min-w-full divide-y divide-gray-200">
|
17
32
|
<thead>
|
18
|
-
<tr>
|
19
|
-
<% resource.attributes.each do |attribute| %>
|
20
|
-
<% next if attribute
|
21
|
-
<% next unless attribute
|
33
|
+
<tr class="border-b border-gray-200">
|
34
|
+
<% resource.attributes.values.each do |attribute| %>
|
35
|
+
<% next if attribute.field.nil? %>
|
36
|
+
<% next unless attribute.field.visible?(action_name) %>
|
22
37
|
|
23
|
-
<th><%= attribute
|
38
|
+
<th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase whitespace-nowrap"><%= sortable attribute.name, attribute.name.to_s.titleize %></th>
|
24
39
|
<% end %>
|
25
|
-
<th>Actions</th>
|
40
|
+
<th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase">Actions</th>
|
26
41
|
</tr>
|
27
42
|
</thead>
|
28
43
|
|
29
|
-
<tbody>
|
44
|
+
<tbody class="text-sm divide-y">
|
30
45
|
<% @records.each do |record| %>
|
31
46
|
<tr>
|
32
|
-
<% resource.attributes.each do |attribute| %>
|
33
|
-
<% next if attribute
|
34
|
-
<% next unless attribute
|
35
|
-
|
36
|
-
<% field = attribute[:field] %>
|
37
|
-
|
38
|
-
<td><%= render partial: field.to_partial_path("index"), locals: { field: field, record: record } %></td>
|
47
|
+
<% resource.attributes.values.each do |attribute| %>
|
48
|
+
<% next if attribute.field.nil? %>
|
49
|
+
<% next unless attribute.field.visible?(action_name) %>
|
50
|
+
<td class="px-4 py-2"><%= render partial: attribute.field.to_partial_path("index"), locals: { field: attribute.field, record: record } %></td>
|
39
51
|
<% end %>
|
40
52
|
|
41
|
-
<td><%= link_to "View", resource.show_path(record) %></td>
|
53
|
+
<td class="px-4 py-2 text-center"><%= link_to "View", resource.show_path(record), class: "text-indigo-500" %></td>
|
42
54
|
</tr>
|
43
55
|
<% end %>
|
44
56
|
</tbody>
|