madmin 1.2.2 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '05151328dcf6fdd8c23755a1b1f3f14b9dcceadc8215e6f102e133d915e95be6'
4
- data.tar.gz: 305bf51253018fa0c871d0314e9ecd69339c510160cdacf1439c2fd361a95a97
3
+ metadata.gz: 79be87e2c5e4bb8b7734ebfac9b623459491a836412bbd0faf077033e6a725ff
4
+ data.tar.gz: a5f93e689c76e156ab396b7da05d47148e19b9ed7bd1f136c4a13b3530c1852a
5
5
  SHA512:
6
- metadata.gz: 625d77d1c5ee5bd30462c2609a8b53b7c5d321fb97e0951a95b852eca019189d468c596fcda77e170ed996bd25707feea787a3668faf318a542a65f03d75e488
7
- data.tar.gz: b594b3c324289e44dbdeb3f0acc70a532b391f8c46faa4854ea5654e9dfe648c88062e24c29433bb476165134a0d79fdbbca526000bbf6c148e9c2c28777f0ed
6
+ metadata.gz: 8bde02b65e86325f630bb2de481a3612e1ae5544891ac3e77bc5ffa78eb158eb6f5603967729040ac408a47f337b42375897848ba89e38a7723ff072dbb97703
7
+ data.tar.gz: c709b74a65fef5383582e3577268dc61e85cb085ce233da6218b586fcf990da32ef5d60cb4991251b3a6b4485f660e018952135233ba23a3bdfeaadfcdbf459a
@@ -0,0 +1,22 @@
1
+ module Madmin
2
+ class ApplicationController < Madmin::BaseController
3
+ before_action :authenticate_admin_user
4
+
5
+ def authenticate_admin_user
6
+ # TODO: Add your authentication logic here
7
+
8
+ # For example, we could redirect if the user isn't an admin
9
+ # redirect_to "/", alert: "Not authorized." unless user_signed_in? && current_user.admin?
10
+ end
11
+
12
+ # Authenticate with Clearance
13
+ # include Clearance::Controller
14
+ # before_action :require_login
15
+
16
+ # Authenticate with Devise
17
+ # before_action :authenticate_user!
18
+
19
+ # Authenticate with Basic Auth
20
+ # http_basic_authenticate_with(name: Rails.application.credentials.admin_username, password: Rails.application.credentials.admin_password)
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  module Madmin
2
- class DashboardController < ApplicationController
2
+ class DashboardController < Madmin::ApplicationController
3
3
  def show
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Madmin
2
- class ResourceController < ApplicationController
2
+ class ResourceController < Madmin::ApplicationController
3
3
  include SortHelper
4
4
 
5
5
  before_action :set_record, except: [:index, :new, :create]
@@ -15,7 +15,7 @@ module Madmin
15
15
  end
16
16
 
17
17
  def clear_search_params
18
- params.except(:q, :_page).permit(:page, :sort, :direction)
18
+ resource.index_path(params.permit(:sort, :direction))
19
19
  end
20
20
  end
21
21
  end
@@ -4,7 +4,7 @@ module Madmin
4
4
  matching_column = (column.to_s == sort_column)
5
5
  direction = sort_direction == "asc" ? "desc" : "asc"
6
6
 
7
- link_to request.params.merge(sort: column, direction: direction), options do
7
+ link_to resource.index_path(sort: column, direction: direction), options do
8
8
  concat title
9
9
  if matching_column
10
10
  concat " "
@@ -3,13 +3,13 @@
3
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, Controller } from 'https://cdn.skypack.dev/stimulus'
6
+ import { Application, Controller } from 'https://cdn.skypack.dev/@hotwired/stimulus'
7
7
  const application = Application.start()
8
8
 
9
9
  import { Dropdown } from "https://cdn.skypack.dev/tailwindcss-stimulus-components"
10
10
  application.register("dropdown", Dropdown)
11
11
 
12
- import stimulusFlatpickr from 'https://cdn.skypack.dev/stimulus-flatpickr'
12
+ import stimulusFlatpickr from 'https://cdn.skypack.dev/stimulus-flatpickr@3.0.0-0'
13
13
  application.register("flatpickr", stimulusFlatpickr)
14
14
 
15
15
  import TomSelect from 'https://cdn.skypack.dev/tom-select'
@@ -38,7 +38,8 @@
38
38
  labelField: 'name',
39
39
  searchField: 'name',
40
40
  load: (search, callback) => {
41
- fetch(this.urlValue)
41
+ let url = search ? `${this.urlValue}?q=${search}` : this.urlValue;
42
+ fetch(url)
42
43
  .then(response => response.json())
43
44
  .then(json => {
44
45
  callback(json);
@@ -27,33 +27,36 @@
27
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}) %>
28
28
  <% end %>
29
29
  </div>
30
-
31
- <table class="min-w-full divide-y divide-gray-200">
32
- <thead>
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) %>
37
-
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>
39
- <% end %>
40
- <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase">Actions</th>
41
- </tr>
42
- </thead>
43
-
44
- <tbody class="text-sm divide-y">
45
- <% @records.each do |record| %>
46
- <tr>
30
+ <div class="min-w-full max-w-xl overflow-x-auto pb-4">
31
+ <table class="min-w-full divide-y divide-gray-200">
32
+ <thead>
33
+ <tr class="border-b border-gray-200">
47
34
  <% resource.attributes.values.each do |attribute| %>
48
35
  <% next if attribute.field.nil? %>
49
36
  <% 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>
51
- <% end %>
52
37
 
53
- <td class="px-4 py-2 text-center"><%= link_to "View", resource.show_path(record), class: "text-indigo-500" %></td>
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>
39
+ <% end %>
40
+ <th class="py-2 px-4 text-left text-xs text-gray-500 font-medium uppercase">Actions</th>
54
41
  </tr>
55
- <% end %>
56
- </tbody>
57
- </table>
58
-
42
+ </thead>
43
+
44
+ <tbody class="text-sm divide-y">
45
+ <% @records.each do |record| %>
46
+ <tr>
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, resource: resource } %></td>
51
+ <% end %>
52
+
53
+ <td class="px-4 py-2 text-center">
54
+ <%= link_to "View", resource.show_path(record), class: "text-indigo-500" %>
55
+ <%= link_to "Edit", resource.edit_path(record), class: "text-indigo-500" %>
56
+ </td>
57
+ </tr>
58
+ <% end %>
59
+ </tbody>
60
+ </table>
61
+ </div>
59
62
  <%== pagy_nav(@pagy) if @pagy.pages > 1 %>
@@ -24,7 +24,7 @@
24
24
  </div>
25
25
 
26
26
  <div class="md:col-span-3">
27
- <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record } %>
27
+ <%= render partial: attribute.field.to_partial_path("show"), locals: { field: attribute.field, record: @record, resource: resource } %>
28
28
  </div>
29
29
  </div>
30
30
  <% end %>
@@ -1,3 +1,3 @@
1
1
  <% if (attachment = field.value(record)) && attachment.attached? %>
2
- <%= link_to attachment.filename, attachment, target: :_blank %>
2
+ <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank %>
3
3
  <% end %>
@@ -1,9 +1,9 @@
1
1
  <% if (attachment = field.value(record)) && attachment.attached? %>
2
2
  <% if attachment.variable? %>
3
- <%= link_to attachment, target: :_blank do %>
4
- <%= image_tag attachment, class: "max-h-32" %>
3
+ <%= link_to main_app.url_for(attachment), target: :_blank do %>
4
+ <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
5
5
  <% end %>
6
6
  <% else %>
7
- <%= link_to attachment.filename, attachment, target: :_blank, class: "text-indigo-500 underline" %>
7
+ <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-indigo-500 underline" %>
8
8
  <% end %>
9
- <% end %>
9
+ <% end %>
@@ -1,11 +1,11 @@
1
1
  <% if (attachments = field.value(record)) && attachments.attached? %>
2
2
  <% attachments.each do |attachment| %>
3
3
  <% if attachment.variable? %>
4
- <%= link_to attachment, target: :_blank do %>
5
- <%= image_tag attachment, class: "max-h-32" %>
4
+ <%= link_to main_app.url_for(attachment), target: :_blank do %>
5
+ <%= image_tag main_app.url_for(attachment), class: "max-h-32" %>
6
6
  <% end %>
7
7
  <% else %>
8
- <%= link_to attachment.filename, attachment, target: :_blank, class: "text-indigo-500 underline" %>
8
+ <%= link_to attachment.filename, main_app.url_for(attachment), target: :_blank, class: "text-indigo-500 underline" %>
9
9
  <% end %>
10
10
  <% end %>
11
11
  <% end %>
@@ -0,0 +1,4 @@
1
+ <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
+ <%= render "madmin/shared/label", form: form, field: field %>
3
+ </div>
4
+ <%= form.file_field field.attribute_name, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1,6 @@
1
+ <% value = field.value(record) %>
2
+ <% if value.respond_to?(:url) %>
3
+ <%= link_to value.url, value.url, target: :_blank, class: "text-indigo-500 underline" %>
4
+ <% else %>
5
+ <%= value %>
6
+ <% end %>
@@ -1 +1,5 @@
1
- <%= field.value(record) %>
1
+ <% if field.attribute_name == :id %>
2
+ <%= link_to field.value(record), resource.show_path(record), class: "text-indigo-500 underline" %>
3
+ <% else %>
4
+ <%= field.value(record) %>
5
+ <% end %>
@@ -1,5 +1,5 @@
1
- <%= content_tag :div, class: "nested-fields bg-gray-100 rounded-t-xl p-5", data: { new_record: f.object.new_record? } do %>
2
- <% field.nested_attributes.each do |nested_attribute| %>
1
+ <%= content_tag :div, class: "nested-fields border border-gray-200 rounded-lg p-5", data: { new_record: f.object.new_record? } do %>
2
+ <% field.nested_attributes.each do |name, nested_attribute| %>
3
3
  <% next if nested_attribute[:field].nil? %>
4
4
  <% next unless nested_attribute[:field].visible?(action_name) %>
5
5
  <% next unless nested_attribute[:field].visible?(:form) %>
@@ -14,5 +14,4 @@
14
14
  <small><%= link_to "Remove", "#", data: { action: "click->nested-form#remove_association" } %></small>
15
15
 
16
16
  <%= f.hidden_field :_destroy %>
17
-
18
17
  <% end %>
@@ -1 +1 @@
1
- <%= field.value(record) %>
1
+ <%= truncate field.value(record).to_s %>
@@ -1,2 +1,4 @@
1
- <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
1
+ <div class="block md:inline-block md:w-32 flex-shrink-0 text-gray-700">
2
+ <%= render "madmin/shared/label", form: form, field: field %>
3
+ </div>
2
4
  <%= form.text_field field.attribute_name, class: "form-input" %>
data/lib/madmin/engine.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  module Madmin
2
2
  class Engine < ::Rails::Engine
3
+ isolate_namespace Madmin
4
+
3
5
  config.before_configuration do |app|
4
- app.config.autoload_paths << File.expand_path("app/madmin/resources", Rails.root)
5
- app.config.autoload_paths << File.expand_path("app/madmin/fields", Rails.root)
6
+ app.config.eager_load_paths << File.expand_path("app/madmin/resources", Rails.root)
7
+ app.config.eager_load_paths << File.expand_path("app/madmin/fields", Rails.root)
6
8
  end
7
9
 
8
10
  config.to_prepare do
data/lib/madmin/field.rb CHANGED
@@ -1,14 +1,15 @@
1
1
  module Madmin
2
2
  class Field
3
- attr_reader :attribute_name, :model, :options
3
+ attr_reader :attribute_name, :model, :options, :resource
4
4
 
5
5
  def self.field_type
6
6
  to_s.split("::").last.underscore
7
7
  end
8
8
 
9
- def initialize(attribute_name:, model:, **options)
9
+ def initialize(attribute_name:, model:, resource:, **options)
10
10
  @attribute_name = attribute_name
11
11
  @model = model
12
+ @resource = resource
12
13
  @options = options
13
14
  end
14
15
 
@@ -0,0 +1,9 @@
1
+ module Madmin
2
+ module Fields
3
+ class File < Field
4
+ def searchable?
5
+ false
6
+ end
7
+ end
8
+ end
9
+ end
@@ -3,7 +3,7 @@ module Madmin
3
3
  class NestedHasMany < Field
4
4
  DEFAULT_ATTRIBUTES = %w[_destroy id].freeze
5
5
  def nested_attributes
6
- resource.attributes.reject { |i| skipped_fields.include?(i[:name]) }
6
+ resource.attributes.reject { |name, attribute| skipped_fields.include?(name) }
7
7
  end
8
8
 
9
9
  def resource
@@ -11,7 +11,7 @@ module Madmin
11
11
  end
12
12
 
13
13
  def model
14
- model_name.constantize
14
+ @model ||= model_name.constantize
15
15
  end
16
16
 
17
17
  def model_find(id)
@@ -37,7 +37,7 @@ module Madmin
37
37
  attributes[name] = OpenStruct.new(
38
38
  name: name,
39
39
  type: type,
40
- field: field.new(**options.merge(attribute_name: name, model: model))
40
+ field: field.new(**options.merge(attribute_name: name, model: model, resource: self))
41
41
  )
42
42
  rescue => e
43
43
  builder = ResourceBuilder.new(model)
@@ -55,31 +55,33 @@ module Madmin
55
55
  end
56
56
 
57
57
  def friendly_name
58
- model_name.gsub("::", " / ")
58
+ model_name.gsub("::", " / ").split(/(?=[A-Z])/).join(" ")
59
59
  end
60
60
 
61
- def index_path(options = {})
62
- route_name = "madmin_#{model.model_name.plural}_path"
61
+ # Support for isolated namespaces
62
+ # Finds parent module class to include in polymorphic urls
63
+ def route_namespace
64
+ return @route_namespace if instance_variable_defined?(:@route_namespace)
65
+ namespace = model.module_parents.detect do |n|
66
+ n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
67
+ end
68
+ @route_namespace = (namespace ? namespace.name.singularize.underscore.to_sym : nil)
69
+ end
63
70
 
64
- url_helpers.send(route_name, options)
71
+ def index_path(options = {})
72
+ url_helpers.polymorphic_path([:madmin, route_namespace, model], options)
65
73
  end
66
74
 
67
75
  def new_path
68
- route_name = "new_madmin_#{model.model_name.singular}_path"
69
-
70
- url_helpers.send(route_name)
76
+ url_helpers.polymorphic_path([:madmin, route_namespace, model], action: :new)
71
77
  end
72
78
 
73
79
  def show_path(record)
74
- route_name = "madmin_#{model.model_name.singular}_path"
75
-
76
- url_helpers.send(route_name, record.to_param)
80
+ url_helpers.polymorphic_path([:madmin, route_namespace, record])
77
81
  end
78
82
 
79
83
  def edit_path(record)
80
- route_name = "edit_madmin_#{model.model_name.singular}_path"
81
-
82
- url_helpers.send(route_name, record.to_param)
84
+ url_helpers.polymorphic_path([:madmin, route_namespace, record], action: :edit)
83
85
  end
84
86
 
85
87
  def param_key
@@ -87,7 +89,7 @@ module Madmin
87
89
  end
88
90
 
89
91
  def permitted_params
90
- attributes.values.filter_map { |a| a.field.to_param if a.field.visible?(:form) }
92
+ attributes.values.filter { |a| a.field.visible?(:form) }.map { |a| a.field.to_param }
91
93
  end
92
94
 
93
95
  def display_name(record)
@@ -128,6 +130,7 @@ module Madmin
128
130
  time: Fields::Time,
129
131
  timestamp: Fields::Time,
130
132
  password: Fields::Password,
133
+ file: Fields::File,
131
134
 
132
135
  # Postgres specific types
133
136
  bit: Fields::String,
@@ -1,3 +1,3 @@
1
1
  module Madmin
2
- VERSION = "1.2.2"
2
+ VERSION = "1.2.6"
3
3
  end
data/lib/madmin.rb CHANGED
@@ -18,6 +18,7 @@ module Madmin
18
18
  autoload :DateTime, "madmin/fields/date_time"
19
19
  autoload :Decimal, "madmin/fields/decimal"
20
20
  autoload :Enum, "madmin/fields/enum"
21
+ autoload :File, "madmin/fields/file"
21
22
  autoload :Float, "madmin/fields/float"
22
23
  autoload :HasMany, "madmin/fields/has_many"
23
24
  autoload :HasOne, "madmin/fields/has_one"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-09-23 00:00:00.000000000 Z
12
+ date: 2021-12-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: '3.5'
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: '5.0'
37
+ version: '6.0'
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: '3.5'
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.0'
47
+ version: '6.0'
48
48
  description: It's an admin, obviously.
49
49
  email:
50
50
  - excid3@gmail.com
@@ -59,6 +59,7 @@ files:
59
59
  - app/assets/config/manifest.js
60
60
  - app/assets/stylesheets/actiontext.scss
61
61
  - app/assets/stylesheets/application.css
62
+ - app/controllers/madmin/application_controller.rb
62
63
  - app/controllers/madmin/base_controller.rb
63
64
  - app/controllers/madmin/dashboard_controller.rb
64
65
  - app/controllers/madmin/resource_controller.rb
@@ -98,6 +99,9 @@ files:
98
99
  - app/views/madmin/fields/enum/_form.html.erb
99
100
  - app/views/madmin/fields/enum/_index.html.erb
100
101
  - app/views/madmin/fields/enum/_show.html.erb
102
+ - app/views/madmin/fields/file/_form.html.erb
103
+ - app/views/madmin/fields/file/_index.html.erb
104
+ - app/views/madmin/fields/file/_show.html.erb
101
105
  - app/views/madmin/fields/float/_form.html.erb
102
106
  - app/views/madmin/fields/float/_index.html.erb
103
107
  - app/views/madmin/fields/float/_show.html.erb
@@ -167,6 +171,7 @@ files:
167
171
  - lib/madmin/fields/date_time.rb
168
172
  - lib/madmin/fields/decimal.rb
169
173
  - lib/madmin/fields/enum.rb
174
+ - lib/madmin/fields/file.rb
170
175
  - lib/madmin/fields/float.rb
171
176
  - lib/madmin/fields/has_many.rb
172
177
  - lib/madmin/fields/has_one.rb
@@ -206,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
211
  - !ruby/object:Gem::Version
207
212
  version: '0'
208
213
  requirements: []
209
- rubygems_version: 3.2.22
214
+ rubygems_version: 3.2.32
210
215
  signing_key:
211
216
  specification_version: 4
212
217
  summary: A modern admin for Ruby on Rails apps