five-two-nw-olivander 0.1.2.17 → 0.1.2.18
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/app/components/olivander/components/resource_form_component.html.haml +10 -0
- data/app/components/olivander/components/resource_form_component.rb +11 -0
- data/app/components/olivander/components/resource_show_component.html.haml +30 -0
- data/app/components/olivander/components/resource_show_component.rb +12 -0
- data/app/controllers/concerns/olivander/resources/auto_form_attributes.rb +126 -0
- data/app/datatables/olivander/datatable.rb +3 -2
- data/app/helpers/olivander/application_helper.rb +46 -6
- data/app/views/application/_form.html.haml +3 -5
- data/app/views/application/_resource_form_actions.html.haml +7 -0
- data/app/views/application/show.html.haml +12 -5
- data/app/views/effective/resource/_actions_dropleft.html.haml +1 -1
- data/lib/olivander/menus/menu_item.rb +0 -3
- data/lib/olivander/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8a36c828d7544eb3e49f262fb2535f738a51e1c12d190eab8faad0d23628fe28
|
|
4
|
+
data.tar.gz: 3c92c632d2a9684280afbc700b5fa2984b85998c24c2856babeaeba77dfe4ee8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eab8679d522df001fb3d21274571af6da60ed1d825b1d5f2b9fbe7e0f13f7c9c48ff7b81a7bc19d77464088ad5c962e91e6d8e51343e72cdd2aba7f78460eb0d
|
|
7
|
+
data.tar.gz: 95283a4df656bb868b541131a1fe21aa2ba16eac4cf38280a6df61666b81f6c728015aadd0df4802c5125d046b2de246a7bdd03740bee84ae44a3f92037c1eb5
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
- @resource.class.resource_field_groups.select{ |x| x.editable }.each do |rfg|
|
|
2
|
+
%h3= resource_field_group_label(@resource.class, rfg.key) unless rfg.key == :default
|
|
3
|
+
- rfg.sections.each do |section|
|
|
4
|
+
.row
|
|
5
|
+
- section.fields.each do |field|
|
|
6
|
+
%div{ class: section.column_class }
|
|
7
|
+
- if field.type == :association
|
|
8
|
+
= @f.association field.sym, disabled: !field.editable
|
|
9
|
+
- else
|
|
10
|
+
= @f.input field.sym, disabled: !field.editable
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Olivander::Components::ResourceFormComponent < ViewComponent::Base
|
|
4
|
+
delegate :resource_field_group_label, to: :helpers
|
|
5
|
+
|
|
6
|
+
def initialize(resource, form_builder)
|
|
7
|
+
@resource = resource
|
|
8
|
+
@f = form_builder
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
- @resource.class.resource_field_groups.each do |rfg|
|
|
2
|
+
%h3= resource_field_group_label(@resource.class, rfg.key) unless rfg.key == :default
|
|
3
|
+
%table.table.table-hover.table-striped
|
|
4
|
+
%thead
|
|
5
|
+
%tr
|
|
6
|
+
- 12.times do
|
|
7
|
+
%td{ style: 'width: 8.33%; height: 0px' }
|
|
8
|
+
%tbody
|
|
9
|
+
- rfg.sections.each do |section|
|
|
10
|
+
- section.fields.each_slice(section.columns) do |slice|
|
|
11
|
+
- colspan = (12 - slice.size) / section.columns
|
|
12
|
+
%tr
|
|
13
|
+
- slice.each do |f|
|
|
14
|
+
%th.text-right{ style: 'width: 10%' }= field_label_for(@resource.class, f.sym)
|
|
15
|
+
- max_columns = rfg.max_section_columns
|
|
16
|
+
%td{ colspan: colspan }
|
|
17
|
+
- val = @resource.send(f.sym)
|
|
18
|
+
- case f.type
|
|
19
|
+
- when :string
|
|
20
|
+
= val
|
|
21
|
+
- when :boolean
|
|
22
|
+
- icon_class = val ? 'fa-check text-success' : 'fa-times text-danger'
|
|
23
|
+
%i.fa{ class: icon_class }
|
|
24
|
+
- when :association
|
|
25
|
+
= link_to val if val.present?
|
|
26
|
+
- else
|
|
27
|
+
= val
|
|
28
|
+
- (section.columns-slice.size).times do
|
|
29
|
+
%th
|
|
30
|
+
%td{ colspan: colspan }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Olivander::Components::ResourceShowComponent < ViewComponent::Base
|
|
4
|
+
delegate :field_label_for, to: :helpers
|
|
5
|
+
delegate :resource_field_group_label, to: :helpers
|
|
6
|
+
|
|
7
|
+
def initialize(resource, actions)
|
|
8
|
+
@resource = resource
|
|
9
|
+
@actions = actions
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -7,6 +7,132 @@ module Olivander
|
|
|
7
7
|
def auto_form_attributes
|
|
8
8
|
attributes.keys - ['updated_at', 'created_at', 'deleted_at']
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
def self.method_missing(m, *args, &block)
|
|
12
|
+
if %i[auto_resource_fields resource_field_groups resource_field_group].include?(m)
|
|
13
|
+
include(Olivander::Resources::ResourceFields)
|
|
14
|
+
send(m, *args, &block)
|
|
15
|
+
else
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ResourceFields
|
|
23
|
+
extend ActiveSupport::Concern
|
|
24
|
+
SKIPPED_ATTRIBUTES = %i[id created_at updated_at deleted_at]
|
|
25
|
+
|
|
26
|
+
included do
|
|
27
|
+
cattr_accessor :current_resource_field_group
|
|
28
|
+
cattr_accessor :current_resource_field_row
|
|
29
|
+
cattr_accessor :resource_field_group_collection
|
|
30
|
+
|
|
31
|
+
def self.resource_field_groups
|
|
32
|
+
auto_resource_fields if self.resource_field_group_collection.nil?
|
|
33
|
+
self.resource_field_group_collection
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.auto_resource_fields(columns: 2, only: [])
|
|
37
|
+
if current_resource_field_group.nil?
|
|
38
|
+
resource_field_group do
|
|
39
|
+
auto_resource_fields(columns: columns, only: only)
|
|
40
|
+
end
|
|
41
|
+
elsif current_resource_field_group.forced_section.nil?
|
|
42
|
+
resource_field_section(columns) do
|
|
43
|
+
auto_resource_fields(columns: columns, only: only)
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
only = self.columns.collect{ |x| x.name.to_sym } - SKIPPED_ATTRIBUTES if only.size.zero?
|
|
47
|
+
self.columns.each do |att|
|
|
48
|
+
sym = att.name.to_sym
|
|
49
|
+
type = att.type
|
|
50
|
+
next unless only.include?(sym)
|
|
51
|
+
|
|
52
|
+
reflections.map{ |x| x[1] }
|
|
53
|
+
.filter{ |x| x.foreign_key == att.name }
|
|
54
|
+
.each do |r|
|
|
55
|
+
sym = r.name
|
|
56
|
+
type = :association
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
resource_field sym, type
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.resource_field_group(key = :default, editable: true, &block)
|
|
65
|
+
self.resource_field_group_collection ||= []
|
|
66
|
+
self.current_resource_field_group = resource_field_group_collection.select{ |x| x.key == key}.first
|
|
67
|
+
unless current_resource_field_group.present?
|
|
68
|
+
self.current_resource_field_group = ResourceFieldGroup.new(key, editable)
|
|
69
|
+
self.resource_field_group_collection << self.current_resource_field_group
|
|
70
|
+
end
|
|
71
|
+
yield
|
|
72
|
+
self.current_resource_field_group = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.resource_field_section(columns = nil, &block)
|
|
76
|
+
self.current_resource_field_group.forced_section = self.current_resource_field_group.next_section(columns)
|
|
77
|
+
yield
|
|
78
|
+
self.current_resource_field_group.forced_section = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.resource_field(sym, type = :string, editable: nil)
|
|
82
|
+
self.current_resource_field_group.add_field(sym, type, editable)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class ResourceFieldGroup
|
|
87
|
+
attr_accessor :fields, :key, :editable, :forced_section, :sections
|
|
88
|
+
|
|
89
|
+
def initialize(key, editable)
|
|
90
|
+
self.key = key
|
|
91
|
+
self.editable = editable
|
|
92
|
+
self.fields = []
|
|
93
|
+
self.sections = []
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def add_field(sym, type, editable)
|
|
97
|
+
e = editable.nil? ? self.editable : editable
|
|
98
|
+
section = forced_section || next_section
|
|
99
|
+
field = ResourceField.new(sym, type, e, self)
|
|
100
|
+
section.fields << field
|
|
101
|
+
fields << field
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def next_section(columns = 1)
|
|
105
|
+
section = ResourceFieldSection.new(columns)
|
|
106
|
+
sections << section
|
|
107
|
+
section
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def max_section_columns
|
|
111
|
+
sections.collect{ |x| x.columns }.max
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
class ResourceFieldSection
|
|
116
|
+
attr_accessor :fields, :columns
|
|
117
|
+
|
|
118
|
+
def initialize(columns = 1)
|
|
119
|
+
self.columns = columns
|
|
120
|
+
self.fields = []
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def column_class
|
|
124
|
+
"col-md-#{12/columns}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class ResourceField
|
|
129
|
+
attr_accessor :sym, :type, :editable
|
|
130
|
+
|
|
131
|
+
def initialize(sym, type, editable, group)
|
|
132
|
+
self.sym = sym
|
|
133
|
+
self.type = type
|
|
134
|
+
self.editable = editable
|
|
135
|
+
end
|
|
10
136
|
end
|
|
11
137
|
end
|
|
12
138
|
end
|
|
@@ -32,14 +32,15 @@ module Olivander
|
|
|
32
32
|
order(order_by[0], order_by[1]) if order_by.size == 2
|
|
33
33
|
bulk_actions_col
|
|
34
34
|
attributes.each do |key|
|
|
35
|
+
label = field_label_for(klazz, key)
|
|
35
36
|
sym = key.gsub('_id', '').to_sym
|
|
36
37
|
visible = show.include?(key) || !(default_hidden.include?(key) || hide.include?(key))
|
|
37
38
|
if link_path.present? && sym == :id
|
|
38
39
|
link_col sym, link_path, :id, visible: visible
|
|
39
40
|
elsif link_path.present? && sym == :name
|
|
40
|
-
link_col sym, link_path,
|
|
41
|
+
link_col sym, link_path, :id, visible: visible
|
|
41
42
|
else
|
|
42
|
-
col sym, visible: visible
|
|
43
|
+
col sym, visible: visible, label: label
|
|
43
44
|
end
|
|
44
45
|
end
|
|
45
46
|
actions_col
|
|
@@ -26,15 +26,32 @@ module Olivander
|
|
|
26
26
|
actions = resource.is_a?(Class) ?
|
|
27
27
|
(routed_resource.unpersisted_crud_actions | routed_resource.collection_actions.select{ |x| !x.crud_action }) :
|
|
28
28
|
(resource.persisted? ? (routed_resource.persisted_crud_actions | routed_resource.member_actions.select{ |x| !x.crud_action }): [])
|
|
29
|
-
actions.reject{ |a| a.sym == for_action }
|
|
29
|
+
actions = actions.reject{ |a| a.sym == for_action || !can?(a.sym, resource) }
|
|
30
|
+
preferred = %i[show edit destroy]
|
|
31
|
+
[].tap do |arr|
|
|
32
|
+
preferred.each do |p|
|
|
33
|
+
actions.each do |a|
|
|
34
|
+
arr << a if a.sym == p
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
arr &&= actions.reject{ |x| preferred.include?(x.sym) }
|
|
38
|
+
end
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
def resource_form_actions(route_builder, resource, for_action: :show)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
render partial: 'resource_form_actions', locals: { actions: authorized_resource_actions(route_builder, resource, for_action: for_action).select(&:show_in_form) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def resource_form_action_label(resource, action)
|
|
46
|
+
return I18n.t("activerecord.actions.#{resource}.#{action}") if I18n.exists?("activerecord.actions.#{resource}.#{action}")
|
|
47
|
+
return I18n.t("activerecord.actions.#{action}") if I18n.exists?("activerecord.actions.#{action}")
|
|
48
|
+
|
|
49
|
+
action.to_s.titleize
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def resource_field_group_label(resource_class, key)
|
|
53
|
+
i18n_key = "activerecord.attributes.#{resource_class.name.underscore}.resource_field_groups.#{key}"
|
|
54
|
+
I18n.exists?(i18n_key) ? I18n.t(i18n_key) : key.to_s.titleize
|
|
38
55
|
end
|
|
39
56
|
|
|
40
57
|
def current_user
|
|
@@ -44,5 +61,28 @@ module Olivander
|
|
|
44
61
|
def current_ability
|
|
45
62
|
controller.respond_to?(:current_ability) ? controller.current_ability : nil
|
|
46
63
|
end
|
|
64
|
+
|
|
65
|
+
def resource_attributes(resource, effective_resource)
|
|
66
|
+
er_attributes = effective_resource&.model_attributes&.collect{ |x| x[0] }
|
|
67
|
+
return er_attributes if er_attributes.present? && er_attributes.size.positive?
|
|
68
|
+
|
|
69
|
+
resource.auto_form_attributes
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def render_optional_partial partial
|
|
73
|
+
begin
|
|
74
|
+
render partial: partial
|
|
75
|
+
rescue ActionView::MissingTemplate
|
|
76
|
+
Rails.logger.debug "did not find partial: #{partial}"
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def field_label_for(resource_class, sym)
|
|
82
|
+
i18n_key = "activerecord.attributes.#{resource_class.name.underscore}.#{sym}"
|
|
83
|
+
return I18n.t(i18n_key) if I18n.exists?(i18n_key)
|
|
84
|
+
|
|
85
|
+
sym.to_s.titleize
|
|
86
|
+
end
|
|
47
87
|
end
|
|
48
88
|
end
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
= simple_form_for(@resource) do |f|
|
|
3
3
|
.card.card-primary
|
|
4
4
|
.card-header
|
|
5
|
+
%h3.card-title= @resource
|
|
5
6
|
.card-tools
|
|
6
7
|
= resource_form_actions(@context.route_builder, @resource, for_action: action_name.to_sym)
|
|
7
8
|
.card-body
|
|
8
9
|
=f.error_notification
|
|
9
10
|
=f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present?
|
|
10
|
-
|
|
11
|
-
.row
|
|
12
|
-
.col-12
|
|
13
|
-
= f.input a, disabled: read_only
|
|
11
|
+
= render Olivander::Components::ResourceFormComponent.new(@resource, f)
|
|
14
12
|
.card-footer.text-right
|
|
15
13
|
= link_to 'Cancel', @_effective_resource.action_path(:index), class: 'btn btn-secondary'
|
|
16
14
|
- unless read_only
|
|
17
|
-
= f.button :submit, class: 'btn btn-primary'
|
|
15
|
+
= f.button :submit, class: 'btn btn-primary'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- actions.each do |a|
|
|
2
|
+
= link_to controller: a.controller, action: a.action, method: a.verb, class: 'btn btn-tool', data: { turbo: true } do
|
|
3
|
+
- icon_key = "activerecord.actions.icons.#{a.sym}"
|
|
4
|
+
- if I18n.exists?(icon_key)
|
|
5
|
+
%i.fa{ class: I18n.t(icon_key)}
|
|
6
|
+
= resource_form_action_label(@resource, a.sym)
|
|
7
|
+
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
- resource = (@_effective_resource || Effective::Resource.new(controller_path))
|
|
2
2
|
- @resource = instance_variable_get('@' + resource.name) if resource.name
|
|
3
3
|
|
|
4
|
+
= render_optional_partial 'show_before'
|
|
5
|
+
|
|
4
6
|
- if @resource
|
|
5
7
|
.row
|
|
6
8
|
.col-12
|
|
7
|
-
|
|
9
|
+
.card.card-primary
|
|
10
|
+
.card-header
|
|
11
|
+
%h3.card-title= @resource.to_s
|
|
12
|
+
.card-tools
|
|
13
|
+
= resource_form_actions(@context.route_builder, @resource, for_action: action_name.to_sym)
|
|
14
|
+
.card-body
|
|
15
|
+
= render Olivander::Components::ResourceShowComponent.new(@resource, [])
|
|
16
|
+
.card-footer.text-right
|
|
17
|
+
= link_to 'Cancel', @_effective_resource.action_path(:index), class: 'btn btn-secondary'
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
= render partial: 'show_additional'
|
|
11
|
-
- rescue ActionView::MissingTemplate
|
|
12
|
-
- Rails.logger.debug "did not find additional show partial"
|
|
19
|
+
= render_optional_partial 'show_after'
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
= dropdown(variation: :dropleft, btn_class: btn_class) do
|
|
3
3
|
- authorized_resource_actions(route_builder, resource, for_action: action_name).select{ |x| x.show_in_datatable }.each do |a|
|
|
4
4
|
- path = a.path_helper.is_a?(Proc) ? a.path_helper.call(resource) : send(a.path_helper, resource.id)
|
|
5
|
-
= dropdown_link_to a.sym, path
|
|
5
|
+
= dropdown_link_to resource_form_action_label(resource, a.sym), path
|
|
@@ -42,7 +42,6 @@ module Olivander
|
|
|
42
42
|
@submenu_items ||= [].tap do |arr|
|
|
43
43
|
if visible
|
|
44
44
|
@submenu_items_blocks.each do |block|
|
|
45
|
-
Rails.logger.debug "invoking submenu item block on #{@key}"
|
|
46
45
|
block.call.each { |item| arr << item if item.visible }
|
|
47
46
|
end
|
|
48
47
|
end
|
|
@@ -58,7 +57,6 @@ module Olivander
|
|
|
58
57
|
@badges ||= [].tap do |arr|
|
|
59
58
|
if visible
|
|
60
59
|
@badges_blocks.each do |block|
|
|
61
|
-
Rails.logger.debug "invoking badge block on #{@key}"
|
|
62
60
|
block.call.each { |badge| arr << badge }
|
|
63
61
|
end
|
|
64
62
|
end
|
|
@@ -69,7 +67,6 @@ module Olivander
|
|
|
69
67
|
|
|
70
68
|
def evaluate_conditions_block
|
|
71
69
|
if @conditions_block
|
|
72
|
-
Rails.logger.debug "invoking condition on #{@key}"
|
|
73
70
|
@conditions_block.call
|
|
74
71
|
else
|
|
75
72
|
true
|
data/lib/olivander/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: five-two-nw-olivander
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.2.
|
|
4
|
+
version: 0.1.2.18
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Dennis
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-07-
|
|
11
|
+
date: 2023-07-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: chartkick
|
|
@@ -185,6 +185,10 @@ files:
|
|
|
185
185
|
- app/assets/stylesheets/olivander/application.css
|
|
186
186
|
- app/components/olivander/components/menu_item_component.html.haml
|
|
187
187
|
- app/components/olivander/components/menu_item_component.rb
|
|
188
|
+
- app/components/olivander/components/resource_form_component.html.haml
|
|
189
|
+
- app/components/olivander/components/resource_form_component.rb
|
|
190
|
+
- app/components/olivander/components/resource_show_component.html.haml
|
|
191
|
+
- app/components/olivander/components/resource_show_component.rb
|
|
188
192
|
- app/controllers/concerns/olivander/resources/auto_form_attributes.rb
|
|
189
193
|
- app/controllers/concerns/olivander/resources/route_builder.rb
|
|
190
194
|
- app/controllers/olivander/application_controller.rb
|
|
@@ -194,6 +198,7 @@ files:
|
|
|
194
198
|
- app/mailers/olivander/application_mailer.rb
|
|
195
199
|
- app/models/olivander/application_record.rb
|
|
196
200
|
- app/views/application/_form.html.haml
|
|
201
|
+
- app/views/application/_resource_form_actions.html.haml
|
|
197
202
|
- app/views/application/edit.html.haml
|
|
198
203
|
- app/views/application/index.html.haml
|
|
199
204
|
- app/views/application/new.html.haml
|