yummy-guide-generic-administrate 0.1.0
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 +7 -0
- data/Gemfile +4 -0
- data/README.md +243 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/yummy_guide_administrate/filter_form.js +219 -0
- data/app/assets/javascripts/yummy_guide_administrate/sticky_left_columns.js +141 -0
- data/app/assets/stylesheets/yummy_guide_administrate/components.scss +199 -0
- data/app/controllers/concerns/yummy_guide/administrate/datetime_filter_parameters.rb +40 -0
- data/app/controllers/concerns/yummy_guide/administrate/default_sorting.rb +46 -0
- data/app/dashboards/yummy_guide/administrate/application_dashboard.rb +46 -0
- data/app/fields/yummy_guide/administrate/fields/area/picture_field.rb +106 -0
- data/app/fields/yummy_guide/administrate/fields/json_pretty_field.rb +29 -0
- data/app/fields/yummy_guide/administrate/fields/version_item_field.rb +62 -0
- data/app/fields/yummy_guide/administrate/fields/version_whodunnit_field.rb +65 -0
- data/app/helpers/yummy_guide/administrate/collection_helper.rb +62 -0
- data/app/helpers/yummy_guide/administrate/filter_form_helper.rb +80 -0
- data/app/views/fields/yummy_guide_administrate/area/picture/_form.html.erb +36 -0
- data/app/views/fields/yummy_guide_administrate/area/picture/_index.html.erb +2 -0
- data/app/views/fields/yummy_guide_administrate/area/picture/_show.html.erb +24 -0
- data/app/views/fields/yummy_guide_administrate/json_pretty_field/_index.html.erb +2 -0
- data/app/views/fields/yummy_guide_administrate/json_pretty_field/_show.html.erb +6 -0
- data/app/views/fields/yummy_guide_administrate/version_item_field/_index.html.erb +2 -0
- data/app/views/fields/yummy_guide_administrate/version_item_field/_show.html.erb +6 -0
- data/app/views/fields/yummy_guide_administrate/version_whodunnit_field/_index.html.erb +2 -0
- data/app/views/fields/yummy_guide_administrate/version_whodunnit_field/_show.html.erb +6 -0
- data/app/views/yummy_guide/administrate/administrate/application/_collection.html.erb +62 -0
- data/app/views/yummy_guide/administrate/filter_forms/_checkbox_group.html.erb +30 -0
- data/app/views/yummy_guide/administrate/filter_forms/_datetime_field.html.erb +30 -0
- data/app/views/yummy_guide/administrate/filter_forms/_frame.html.erb +28 -0
- data/lib/generic/administrate.rb +3 -0
- data/lib/yummy_guide/administrate/engine.rb +18 -0
- data/lib/yummy_guide/administrate/version.rb +8 -0
- data/lib/yummy_guide/administrate.rb +13 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/yummy_guide/administrate/application_dashboard_spec.rb +39 -0
- data/spec/yummy_guide/administrate/collection_helper_spec.rb +25 -0
- data/spec/yummy_guide/administrate/datetime_filter_parameters_spec.rb +52 -0
- data/spec/yummy_guide/administrate/fields/json_pretty_field_spec.rb +22 -0
- data/spec/yummy_guide/administrate/fields/version_item_field_spec.rb +30 -0
- data/spec/yummy_guide/administrate/fields/version_whodunnit_field_spec.rb +31 -0
- data/spec/yummy_guide/administrate/filter_form_helper_spec.rb +40 -0
- data/yummy-guide-generic-administrate.gemspec +38 -0
- metadata +156 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
.scroll-table {
|
|
2
|
+
overflow-x: auto;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.scroll-table table th.sticky-left,
|
|
6
|
+
.scroll-table table td.sticky-left {
|
|
7
|
+
position: sticky;
|
|
8
|
+
background-clip: padding-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.scroll-table table th.sticky-left {
|
|
12
|
+
z-index: 4;
|
|
13
|
+
background-color: #121012;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.scroll-table table td.sticky-left {
|
|
17
|
+
z-index: 3;
|
|
18
|
+
background-color: var(--sticky-cell-background, #fff);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.scroll-table table th.sticky-left::after,
|
|
22
|
+
.scroll-table table td.sticky-left::after {
|
|
23
|
+
content: "";
|
|
24
|
+
position: absolute;
|
|
25
|
+
top: -1px;
|
|
26
|
+
right: -1px;
|
|
27
|
+
bottom: -1px;
|
|
28
|
+
width: 1px;
|
|
29
|
+
background-color: #fff;
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.scroll-table table th.sticky-left--last,
|
|
34
|
+
.scroll-table table td.sticky-left--last {
|
|
35
|
+
box-shadow: 6px 0 8px -8px rgba(0, 0, 0, 0.35);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.yummy-guide-administrate-filter-form {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
gap: 0;
|
|
42
|
+
background: #fff;
|
|
43
|
+
border: 1px solid #d7dce5;
|
|
44
|
+
border-radius: 12px;
|
|
45
|
+
box-shadow: 0 18px 44px rgba(15, 23, 42, 0.08);
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.yummy-guide-administrate-filter-form__title {
|
|
50
|
+
margin: 0;
|
|
51
|
+
padding: 20px 20px 16px;
|
|
52
|
+
font-size: 1.2rem;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.yummy-guide-administrate-filter-form__body {
|
|
56
|
+
padding: 0 20px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.yummy-guide-administrate-filter-form .filter_table {
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.yummy-guide-administrate-filter-form .filter_table td {
|
|
64
|
+
padding: 8px 0;
|
|
65
|
+
vertical-align: top;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.yummy-guide-administrate-filter-form .filter_table td:first-child {
|
|
69
|
+
width: 160px;
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
vertical-align: middle;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.yummy-guide-administrate-filter-form input[type="text"],
|
|
75
|
+
.yummy-guide-administrate-filter-form input[type="date"],
|
|
76
|
+
.yummy-guide-administrate-filter-form select,
|
|
77
|
+
.yummy-guide-administrate-filter-form textarea,
|
|
78
|
+
.yummy-guide-administrate-filter-form .filter-datetime-group__time {
|
|
79
|
+
width: 100%;
|
|
80
|
+
min-height: 40px;
|
|
81
|
+
height: 40px;
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
border: 1px solid #dfe0e1;
|
|
84
|
+
border-radius: 5px;
|
|
85
|
+
background-color: #fff;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.yummy-guide-administrate-filter-form__actions {
|
|
89
|
+
display: flex;
|
|
90
|
+
gap: 8px;
|
|
91
|
+
justify-content: flex-end;
|
|
92
|
+
align-items: center;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
padding: 12px 20px 20px;
|
|
95
|
+
background: #fff;
|
|
96
|
+
border-top: 1px solid #e5e7eb;
|
|
97
|
+
box-shadow: 0 -12px 24px rgba(15, 23, 42, 0.08);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.filter-datetime-group {
|
|
101
|
+
display: grid;
|
|
102
|
+
grid-template-columns: minmax(180px, 1fr) 88px auto 88px;
|
|
103
|
+
gap: 8px;
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.filter-datetime-group__separator,
|
|
108
|
+
.filter-datetime-range-separator {
|
|
109
|
+
text-align: center;
|
|
110
|
+
margin: 0;
|
|
111
|
+
min-height: 40px;
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.filter-checkbox-group {
|
|
118
|
+
display: grid;
|
|
119
|
+
gap: 12px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.filter-checkbox-group__options {
|
|
123
|
+
display: grid;
|
|
124
|
+
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
125
|
+
gap: 8px 12px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.filter-checkbox-group__actions {
|
|
129
|
+
display: flex;
|
|
130
|
+
gap: 8px;
|
|
131
|
+
justify-content: flex-end;
|
|
132
|
+
align-items: center;
|
|
133
|
+
flex-wrap: wrap;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.json-pretty-field {
|
|
137
|
+
margin: 0;
|
|
138
|
+
white-space: pre-wrap;
|
|
139
|
+
overflow-wrap: anywhere;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.yummy-guide-administrate-picture-list {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex-wrap: wrap;
|
|
145
|
+
gap: 8px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.yummy-guide-administrate-picture-list__item {
|
|
149
|
+
width: 200px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.yummy-guide-administrate-picture-list__image {
|
|
153
|
+
display: block;
|
|
154
|
+
max-width: 100%;
|
|
155
|
+
border-radius: 8px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.yummy-guide-administrate-picture-slots {
|
|
159
|
+
display: grid;
|
|
160
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
161
|
+
gap: 12px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.yummy-guide-administrate-picture-slot {
|
|
165
|
+
display: grid;
|
|
166
|
+
gap: 8px;
|
|
167
|
+
align-content: start;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.yummy-guide-administrate-picture-slot__input {
|
|
171
|
+
width: 100%;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.yummy-guide-administrate-picture-slot__delete {
|
|
175
|
+
display: inline-flex;
|
|
176
|
+
gap: 6px;
|
|
177
|
+
align-items: center;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@media (max-width: 767px) {
|
|
181
|
+
.yummy-guide-administrate-filter-form__title {
|
|
182
|
+
padding: 16px 16px 12px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.yummy-guide-administrate-filter-form__body {
|
|
186
|
+
padding: 0 16px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.yummy-guide-administrate-filter-form__actions,
|
|
190
|
+
.filter-checkbox-group__actions {
|
|
191
|
+
flex-direction: column;
|
|
192
|
+
align-items: stretch;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.filter-datetime-group {
|
|
196
|
+
grid-template-columns: 1fr;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module DatetimeFilterParameters
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def normalize_datetime_filter_params(filters, keys:)
|
|
11
|
+
return filters if filters.blank? || !filters.respond_to?(:deep_dup)
|
|
12
|
+
|
|
13
|
+
normalized_filters = filters.deep_dup
|
|
14
|
+
|
|
15
|
+
Array(keys).map(&:to_s).each do |key|
|
|
16
|
+
date_value = normalized_filters.delete("#{key}_date") || normalized_filters.delete("#{key}_date".to_sym)
|
|
17
|
+
hour_value = normalized_filters.delete("#{key}_hour") || normalized_filters.delete("#{key}_hour".to_sym)
|
|
18
|
+
minute_value = normalized_filters.delete("#{key}_minute") || normalized_filters.delete("#{key}_minute".to_sym)
|
|
19
|
+
next if date_value.nil? && hour_value.nil? && minute_value.nil?
|
|
20
|
+
|
|
21
|
+
date_value = date_value.to_s.strip
|
|
22
|
+
hour_value = hour_value.to_s.strip
|
|
23
|
+
minute_value = minute_value.to_s.strip
|
|
24
|
+
|
|
25
|
+
normalized_filters[key.to_sym] =
|
|
26
|
+
if date_value.blank?
|
|
27
|
+
nil
|
|
28
|
+
elsif hour_value.present? && minute_value.present?
|
|
29
|
+
"#{date_value}T#{hour_value}:#{minute_value}"
|
|
30
|
+
else
|
|
31
|
+
date_value
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
normalized_filters
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module DefaultSorting
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def default_sorting_attribute
|
|
9
|
+
dashboard_sorting_value(:default_sorting_attribute) || super
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def default_sorting_direction
|
|
13
|
+
dashboard_sorting_value(:default_sorting_direction) || super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def sorting_requested?
|
|
19
|
+
order_present?(params) || sorting_param_keys.any? { |key| order_present?(params[key]) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def dashboard_sorting_value(method_name)
|
|
23
|
+
current_dashboard = dashboard
|
|
24
|
+
return unless current_dashboard.respond_to?(method_name)
|
|
25
|
+
|
|
26
|
+
current_dashboard.public_send(method_name)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def sorting_param_keys
|
|
30
|
+
[
|
|
31
|
+
(resource_name if respond_to?(:resource_name, true)),
|
|
32
|
+
(resource_name.to_sym if respond_to?(:resource_name, true) && resource_name.present?),
|
|
33
|
+
controller_name.singularize,
|
|
34
|
+
controller_name.singularize.to_sym
|
|
35
|
+
].compact.uniq
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def order_present?(value)
|
|
39
|
+
return false unless value.is_a?(ActionController::Parameters) || value.is_a?(Hash)
|
|
40
|
+
|
|
41
|
+
value[:order].present? || value["order"].present?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "administrate/base_dashboard"
|
|
4
|
+
|
|
5
|
+
module YummyGuide
|
|
6
|
+
module Administrate
|
|
7
|
+
class ApplicationDashboard < ::Administrate::BaseDashboard
|
|
8
|
+
INDEX_FIXED_COLUMNS_COUNT = 1
|
|
9
|
+
|
|
10
|
+
def default_sorting_attribute
|
|
11
|
+
:created_at
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def default_sorting_direction
|
|
15
|
+
:desc
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.index_fixed_columns_count
|
|
19
|
+
if const_defined?(:INDEX_FIXED_COLUMNS_COUNT, false)
|
|
20
|
+
const_get(:INDEX_FIXED_COLUMNS_COUNT)
|
|
21
|
+
elsif superclass.respond_to?(:index_fixed_columns_count)
|
|
22
|
+
superclass.index_fixed_columns_count
|
|
23
|
+
else
|
|
24
|
+
0
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.collection_sortable_attributes
|
|
29
|
+
if const_defined?(:COLLECTION_SORTABLE_ATTRIBUTES, false)
|
|
30
|
+
const_get(:COLLECTION_SORTABLE_ATTRIBUTES)
|
|
31
|
+
elsif const_defined?(:COLLECTION_ATTRIBUTES, false)
|
|
32
|
+
const_get(:COLLECTION_ATTRIBUTES)
|
|
33
|
+
elsif superclass.respond_to?(:collection_sortable_attributes)
|
|
34
|
+
superclass.collection_sortable_attributes
|
|
35
|
+
else
|
|
36
|
+
[]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.collection_attribute_sortable?(attribute_name)
|
|
41
|
+
collection_sortable_attributes.map(&:to_sym).include?(attribute_name.to_sym)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "administrate/field/base"
|
|
4
|
+
|
|
5
|
+
module YummyGuide
|
|
6
|
+
module Administrate
|
|
7
|
+
module Fields
|
|
8
|
+
module Area
|
|
9
|
+
class PictureField < ::Administrate::Field::Base
|
|
10
|
+
def self.field_type
|
|
11
|
+
"yummy_guide_administrate/area/picture"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def attachments
|
|
15
|
+
@attachments ||=
|
|
16
|
+
if data.respond_to?(:attachments)
|
|
17
|
+
data.attachments.to_a
|
|
18
|
+
elsif data.respond_to?(:attached?) && data.attached?
|
|
19
|
+
[data]
|
|
20
|
+
else
|
|
21
|
+
[]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def max_uploads
|
|
26
|
+
resolved = resolve_option(:max_uploads)
|
|
27
|
+
resolved = resource.class::MAX_PICTURE_UPLOADS if resolved.blank? && resource.class.const_defined?(:MAX_PICTURE_UPLOADS)
|
|
28
|
+
resolved = attachments.size + 1 if resolved.blank?
|
|
29
|
+
|
|
30
|
+
[resolved.to_i, 1].max
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def input_name
|
|
34
|
+
resolve_option(:input_name) || "#{resource_param_key}[#{attribute}][]"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def purge_input_name
|
|
38
|
+
resolve_option(:purge_input_name) || "#{resource_param_key}[#{attribute}_purge_ids][]"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def attachment_label(attachment)
|
|
42
|
+
return attachment.filename.to_s if attachment.respond_to?(:filename)
|
|
43
|
+
|
|
44
|
+
attachment.to_s
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def attachment_identifier(attachment)
|
|
48
|
+
return attachment.id if attachment.respond_to?(:id) && attachment.id.present?
|
|
49
|
+
return attachment.blob_id if attachment.respond_to?(:blob_id) && attachment.blob_id.present?
|
|
50
|
+
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def attachment_url(attachment, view_context:)
|
|
55
|
+
resolve_attachment_url(:attachment_url, attachment, view_context: view_context) || preview_url(attachment, view_context: view_context)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def preview_url(attachment, view_context:)
|
|
59
|
+
resolve_attachment_url(:preview_url, attachment, view_context: view_context) || default_attachment_url(attachment, view_context: view_context)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def resource_param_key
|
|
65
|
+
resource.class.model_name.param_key
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def resolve_option(name)
|
|
69
|
+
option = options[name]
|
|
70
|
+
if option.respond_to?(:call)
|
|
71
|
+
return option.call if option.arity.zero?
|
|
72
|
+
return option.call(resource) if option.arity == 1
|
|
73
|
+
|
|
74
|
+
return option.call(resource, attribute, data)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
option
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def resolve_attachment_url(name, attachment, view_context:)
|
|
81
|
+
resolver = options[name]
|
|
82
|
+
return unless resolver.respond_to?(:call)
|
|
83
|
+
|
|
84
|
+
case resolver.arity
|
|
85
|
+
when 0
|
|
86
|
+
resolver.call
|
|
87
|
+
when 1
|
|
88
|
+
resolver.call(attachment)
|
|
89
|
+
else
|
|
90
|
+
resolver.call(attachment, view_context)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def default_attachment_url(attachment, view_context:)
|
|
95
|
+
return attachment.url if attachment.respond_to?(:url)
|
|
96
|
+
return view_context.rails_blob_path(attachment, only_path: true) if attachment.respond_to?(:blob)
|
|
97
|
+
|
|
98
|
+
nil
|
|
99
|
+
rescue StandardError
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "administrate/field/text"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module YummyGuide
|
|
7
|
+
module Administrate
|
|
8
|
+
module Fields
|
|
9
|
+
class JsonPrettyField < ::Administrate::Field::Text
|
|
10
|
+
def self.field_type
|
|
11
|
+
"yummy_guide_administrate/json_pretty_field"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
return if data.blank?
|
|
16
|
+
|
|
17
|
+
if data.is_a?(String)
|
|
18
|
+
JSON.pretty_generate(JSON.parse(data))
|
|
19
|
+
else
|
|
20
|
+
JSON.pretty_generate(data.as_json)
|
|
21
|
+
end
|
|
22
|
+
rescue JSON::ParserError, TypeError
|
|
23
|
+
data.to_s
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module Fields
|
|
6
|
+
class VersionItemField < ::Administrate::Field::Base
|
|
7
|
+
def self.field_type
|
|
8
|
+
"yummy_guide_administrate/version_item_field"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def target_resource
|
|
12
|
+
@target_resource ||= resolve_target_resource
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def label
|
|
16
|
+
target = target_resource
|
|
17
|
+
return fallback_label if target.blank?
|
|
18
|
+
|
|
19
|
+
"#{target.class.name.demodulize} ##{target.id}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def path
|
|
23
|
+
return if target_resource.blank?
|
|
24
|
+
|
|
25
|
+
Rails.application.routes.url_helpers.polymorphic_path([namespace, target_resource])
|
|
26
|
+
rescue StandardError
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def linkable?
|
|
31
|
+
path.present?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def namespace
|
|
37
|
+
options.fetch(:namespace, :admin)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def resolve_target_resource
|
|
41
|
+
item = data.presence || resource.reify
|
|
42
|
+
normalize_resource(item)
|
|
43
|
+
rescue StandardError
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def normalize_resource(item)
|
|
48
|
+
return if item.blank?
|
|
49
|
+
|
|
50
|
+
return item.globalized_model if item.respond_to?(:globalized_model) && item.globalized_model.present?
|
|
51
|
+
|
|
52
|
+
item
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def fallback_label
|
|
56
|
+
"#{resource.item_type} ##{resource.item_id}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module Fields
|
|
6
|
+
class VersionWhodunnitField < ::Administrate::Field::Base
|
|
7
|
+
def self.field_type
|
|
8
|
+
"yummy_guide_administrate/version_whodunnit_field"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def user
|
|
12
|
+
@user ||= user_class&.find_by(id: data)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def label
|
|
16
|
+
return if data.blank?
|
|
17
|
+
|
|
18
|
+
if user.present?
|
|
19
|
+
custom_label = options[:user_label]
|
|
20
|
+
return custom_label.call(user) if custom_label.respond_to?(:call)
|
|
21
|
+
|
|
22
|
+
if defined?(::UserDashboard)
|
|
23
|
+
dashboard = ::UserDashboard.new
|
|
24
|
+
return dashboard.display_resource(user) if dashboard.respond_to?(:display_resource)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return user.full_name if user.respond_to?(:full_name) && user.full_name.present?
|
|
28
|
+
return user.name if user.respond_to?(:name) && user.name.present?
|
|
29
|
+
|
|
30
|
+
"#{user.class.model_name.human} ##{user.id}"
|
|
31
|
+
else
|
|
32
|
+
"User ##{data}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def path
|
|
37
|
+
return if user.blank?
|
|
38
|
+
|
|
39
|
+
Rails.application.routes.url_helpers.polymorphic_path([namespace, user])
|
|
40
|
+
rescue StandardError
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def linkable?
|
|
45
|
+
path.present?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def namespace
|
|
51
|
+
options.fetch(:namespace, :admin)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def user_class
|
|
55
|
+
candidate = options[:user_class]
|
|
56
|
+
return candidate if candidate.is_a?(Class)
|
|
57
|
+
return candidate.safe_constantize if candidate.respond_to?(:safe_constantize)
|
|
58
|
+
|
|
59
|
+
::User if defined?(::User)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module YummyGuide
|
|
4
|
+
module Administrate
|
|
5
|
+
module CollectionHelper
|
|
6
|
+
def yummy_guide_administrate_collection_table_fixed_columns_count(page:, collection_presenter:)
|
|
7
|
+
return 0 unless page.respond_to?(:instance_variable_defined?) && page.instance_variable_defined?(:@dashboard)
|
|
8
|
+
|
|
9
|
+
dashboard = page.instance_variable_get(:@dashboard)
|
|
10
|
+
return 0 unless dashboard&.class&.respond_to?(:index_fixed_columns_count)
|
|
11
|
+
|
|
12
|
+
fixed_columns_count = dashboard.class.index_fixed_columns_count.to_i
|
|
13
|
+
fixed_columns_count = 0 if fixed_columns_count.negative?
|
|
14
|
+
|
|
15
|
+
attribute_count = collection_presenter.attribute_types.size
|
|
16
|
+
[fixed_columns_count, attribute_count].min
|
|
17
|
+
rescue NoMethodError
|
|
18
|
+
0
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def yummy_guide_administrate_collection_detail_path(resource, namespace:)
|
|
22
|
+
return if resource.blank?
|
|
23
|
+
return if respond_to?(:accessible_action?) && !accessible_action?(resource, :show)
|
|
24
|
+
|
|
25
|
+
polymorphic_path([namespace, resource])
|
|
26
|
+
rescue StandardError
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def yummy_guide_administrate_collection_attribute_path(attribute:, resource:, namespace:)
|
|
31
|
+
if yummy_guide_administrate_collection_reference_link?(attribute)
|
|
32
|
+
yummy_guide_administrate_collection_detail_path(attribute.data, namespace: namespace)
|
|
33
|
+
elsif yummy_guide_administrate_collection_text_link?(attribute)
|
|
34
|
+
yummy_guide_administrate_collection_detail_path(resource, namespace: namespace)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def yummy_guide_administrate_collection_reference_link?(attribute)
|
|
39
|
+
attribute.is_a?(::Administrate::Field::BelongsTo) && attribute.data.present?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def yummy_guide_administrate_collection_text_link?(attribute)
|
|
43
|
+
attribute.respond_to?(:name) && attribute.name.to_s == "id"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def yummy_guide_administrate_collection_wrap(content, href:)
|
|
47
|
+
return content if href.blank?
|
|
48
|
+
|
|
49
|
+
link_to(href, class: "action-show") { content }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def yummy_guide_administrate_collection_actions_partial(partial_name)
|
|
53
|
+
if controller.respond_to?(:controller_path)
|
|
54
|
+
controller_partial = "#{controller.controller_path}/#{partial_name}"
|
|
55
|
+
return controller_partial if lookup_context.exists?(controller_partial, [], true)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
"administrate/application/#{partial_name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|