avo 1.0.0 → 1.1.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +3 -5
- data/Gemfile.lock +76 -79
- data/README.md +3 -1
- data/app/components/avo/common/multiple_file_viewer_component.html.erb +1 -1
- data/app/components/avo/common/single_file_viewer_component.html.erb +1 -1
- data/app/components/avo/edit/fields/belongs_to_field_component.html.erb +0 -1
- data/app/components/avo/edit/fields/belongs_to_field_component.rb +7 -0
- data/app/components/avo/index/fields/gravatar_field_component.html.erb +1 -1
- data/app/components/avo/index/fields/id_field_component.html.erb +1 -1
- data/app/components/avo/index/resource_controls_component.html.erb +6 -6
- data/app/components/avo/show/fields/has_one_field_component.html.erb +1 -1
- data/app/components/avo/views/resource_index_component.html.erb +5 -5
- data/app/components/avo/views/resource_show_component.html.erb +3 -3
- data/app/controllers/avo/application_controller.rb +7 -8
- data/app/helpers/avo/application_helper.rb +0 -24
- data/app/views/avo/partials/_empty_state.html.erb +1 -1
- data/{lib/generators/avo/templates → app/views/avo}/partials/_scripts.html.erb +0 -0
- data/app/views/avo/partials/_view_toggle_button.html.erb +2 -2
- data/app/views/avo/relations/new.html.erb +1 -1
- data/app/views/avo/sidebar/_sidebar.html.erb +11 -2
- data/app/views/layouts/avo/application.html.erb +3 -3
- data/config/webpacker.yml +12 -1
- data/lib/avo/app.rb +14 -1
- data/lib/avo/base_resource.rb +11 -12
- data/lib/avo/fields/belongs_to_field.rb +0 -2
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/eject_generator.rb +55 -0
- data/lib/generators/avo/templates/tool/controller.tt +2 -0
- data/lib/generators/avo/templates/tool/sidebar_item.tt +1 -0
- data/lib/generators/avo/templates/tool/view.tt +27 -0
- data/lib/generators/avo/tool_generator.rb +60 -0
- data/public/avo-packs/css/application-9d115b7e.css.map +1 -1
- data/public/avo-packs/css/application-9d115b7e.css.map.br +0 -0
- data/public/avo-packs/css/application-9d115b7e.css.map.gz +0 -0
- metadata +10 -10
- data/config/webpacker_packed.yml +0 -79
- data/lib/generators/avo/partials_generator.rb +0 -14
- data/lib/generators/avo/templates/partials/_footer.html.erb +0 -3
- data/lib/generators/avo/templates/partials/_header.html.erb +0 -1
- data/lib/generators/avo/templates/partials/_logo.html.erb +0 -1
@@ -4,19 +4,19 @@
|
|
4
4
|
|
5
5
|
<% if can_create? %>
|
6
6
|
<%= a_link create_path do %>
|
7
|
-
<%= svg 'plus' %> <%= t('avo.create_new_item',
|
7
|
+
<%= svg 'plus' %> <%= t('avo.create_new_item', item: @resource.model_class.model_name.human.downcase ) %>
|
8
8
|
<% end %>
|
9
9
|
<% end %>
|
10
10
|
|
11
11
|
<% if can_detach? %>
|
12
12
|
<%= a_link detach_path, color: 'indigo', method: :delete, data: { confirm: "Are you sure you want to detach this #{@resource.singular_name}." } do %>
|
13
|
-
<%= svg 'trash' %> <%= t('avo.detach_item',
|
13
|
+
<%= svg 'trash' %> <%= t('avo.detach_item', item: @resource.singular_name).capitalize %>
|
14
14
|
<% end %>
|
15
15
|
<% end %>
|
16
16
|
|
17
17
|
<% if can_attach? %>
|
18
18
|
<%= a_link attach_path, color: 'indigo', 'data-turbo-frame': 'attach_modal' do %>
|
19
|
-
<%= svg 'view-grid-add' %> <%= t('avo.attach_item',
|
19
|
+
<%= svg 'view-grid-add' %> <%= t('avo.attach_item', item: @resource.singular_name).capitalize %>
|
20
20
|
<% end %>
|
21
21
|
<% end %>
|
22
22
|
<% end %>
|
@@ -43,7 +43,7 @@
|
|
43
43
|
|
44
44
|
<% if @models.present? %>
|
45
45
|
<div class="py-4">
|
46
|
-
<%= render partial: 'avo/partials/paginator', locals: { pagy: @pagy, turbo_frame: @turbo_frame } %>
|
46
|
+
<%= render partial: 'avo/partials/paginator', locals: { pagy: @pagy, turbo_frame: @turbo_frame || 'none' } %>
|
47
47
|
</div>
|
48
48
|
<% end %>
|
49
49
|
</div>
|
@@ -55,7 +55,7 @@
|
|
55
55
|
<%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
|
56
56
|
|
57
57
|
<div class="bg-white rounded-xl shadow-xl mt-8 py-6">
|
58
|
-
<%= render partial: 'avo/partials/paginator', locals: { pagy: @pagy, turbo_frame: @turbo_frame } %>
|
58
|
+
<%= render partial: 'avo/partials/paginator', locals: { pagy: @pagy, turbo_frame: @turbo_frame || 'none' } %>
|
59
59
|
</div>
|
60
60
|
<% end %>
|
61
61
|
<% end %>
|
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
<% if @reflection.present? && @resource.model.present? %>
|
12
12
|
<%= a_link detach_path, color: 'indigo', method: :delete, data: { confirm: "Are you sure you want to detach this #{@resource.singular_name}." } do %>
|
13
|
-
<%= svg 'trash' %> <%= t('avo.detach_item',
|
13
|
+
<%= svg 'trash' %> <%= t('avo.detach_item', item: @resource.singular_name).capitalize %>
|
14
14
|
<% end %>
|
15
15
|
<% else %>
|
16
16
|
<%= a_link back_path do %>
|
@@ -19,12 +19,12 @@
|
|
19
19
|
|
20
20
|
<% if @resource.authorization.authorize_action(:destroy, raise_exception: false) %>
|
21
21
|
<%= form_with url: helpers.resource_path(@resource.model), method: :delete, html: { 'data-turbo-frame': params[:turbo_frame] } do |form| %>
|
22
|
-
<%= a_button title: t('avo.delete_item',
|
22
|
+
<%= a_button title: t('avo.delete_item', item: @resource.model.model_name.name.downcase).capitalize,
|
23
23
|
color: 'red',
|
24
24
|
variant: 'outlined',
|
25
25
|
type: :submit,
|
26
26
|
data: {
|
27
|
-
confirm: t('avo.are_you_sure',
|
27
|
+
confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
|
28
28
|
control: :destroy,
|
29
29
|
'resource-id': @resource.model.id,
|
30
30
|
'tippy': 'tooltip',
|
@@ -51,7 +51,7 @@ module Avo
|
|
51
51
|
existing_params = Addressable::URI.parse(request.fullpath).query_values.symbolize_keys
|
52
52
|
end
|
53
53
|
rescue; end
|
54
|
-
send :"resources_#{model.model_name.route_key}_path", **existing_params, **args
|
54
|
+
avo.send :"resources_#{model.model_name.route_key}_path", **existing_params, **args
|
55
55
|
end
|
56
56
|
|
57
57
|
def related_resources_path(parent_model, model, keep_query_params: false, **args)
|
@@ -70,9 +70,9 @@ module Avo
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def resource_path(model = nil, resource_id: nil, keep_query_params: false, **args)
|
73
|
-
return send :"resources_#{model.model_name.route_key.singularize}_path", resource_id, **args if resource_id.present?
|
73
|
+
return avo.send :"resources_#{model.model_name.route_key.singularize}_path", resource_id, **args if resource_id.present?
|
74
74
|
|
75
|
-
send :"resources_#{model.model_name.route_key.singularize}_path", model, **args
|
75
|
+
avo.send :"resources_#{model.model_name.route_key.singularize}_path", model, **args
|
76
76
|
end
|
77
77
|
|
78
78
|
def resource_attach_path(model_name, model_id, related_name, related_id = nil)
|
@@ -92,11 +92,11 @@ module Avo
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def new_resource_path(model, **args)
|
95
|
-
send :"new_resources_#{model.model_name.route_key.singularize}_path", **args
|
95
|
+
avo.send :"new_resources_#{model.model_name.route_key.singularize}_path", **args
|
96
96
|
end
|
97
97
|
|
98
98
|
def edit_resource_path(model, **args)
|
99
|
-
send :"edit_resources_#{model.model_name.route_key.singularize}_path", model, **args
|
99
|
+
avo.send :"edit_resources_#{model.model_name.route_key.singularize}_path", model, **args
|
100
100
|
end
|
101
101
|
|
102
102
|
private
|
@@ -110,6 +110,8 @@ module Avo
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def set_resource
|
113
|
+
raise ActionController::RoutingError.new "No route matches" if resource.nil?
|
114
|
+
|
113
115
|
@resource = resource.hydrate(params: params)
|
114
116
|
end
|
115
117
|
|
@@ -182,8 +184,6 @@ module Avo
|
|
182
184
|
def eager_load_files(resource, query)
|
183
185
|
if resource.attached_file_fields.present?
|
184
186
|
resource.attached_file_fields.map do |field|
|
185
|
-
# abort "#{field.pluralize}".inspect
|
186
|
-
# abort field.class.inspect
|
187
187
|
attachment = case field.class.to_s
|
188
188
|
when "Avo::Fields::FileField"
|
189
189
|
"attachment"
|
@@ -194,7 +194,6 @@ module Avo
|
|
194
194
|
end
|
195
195
|
|
196
196
|
return query.eager_load "#{field.id}_#{attachment}": :blob
|
197
|
-
# return query.send :"with_attached_#{field}"
|
198
197
|
end
|
199
198
|
end
|
200
199
|
|
@@ -7,30 +7,6 @@ module Avo
|
|
7
7
|
Avo.webpacker
|
8
8
|
end
|
9
9
|
|
10
|
-
def render_logo
|
11
|
-
render partial: "vendor/avo/partials/logo"
|
12
|
-
rescue
|
13
|
-
render partial: "avo/partials/logo"
|
14
|
-
end
|
15
|
-
|
16
|
-
def render_header
|
17
|
-
render partial: "vendor/avo/partials/header"
|
18
|
-
rescue
|
19
|
-
render partial: "avo/partials/header"
|
20
|
-
end
|
21
|
-
|
22
|
-
def render_footer
|
23
|
-
render partial: "vendor/avo/partials/footer"
|
24
|
-
rescue
|
25
|
-
render partial: "avo/partials/footer"
|
26
|
-
end
|
27
|
-
|
28
|
-
def render_scripts
|
29
|
-
render partial: "vendor/avo/partials/scripts"
|
30
|
-
rescue
|
31
|
-
""
|
32
|
-
end
|
33
|
-
|
34
10
|
def render_license_warnings
|
35
11
|
render partial: "avo/sidebar/license_warnings", locals: {
|
36
12
|
license: Avo::App.license.properties
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%
|
2
2
|
classes = 'absolute inset-auto left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2'
|
3
3
|
translation_tag = params[:related_name].present? ? 'avo.no_related_item_found' : 'avo.no_item_found'
|
4
|
-
label = t translation_tag,
|
4
|
+
label = t translation_tag, item: resource_name
|
5
5
|
%>
|
6
6
|
<div class="relative flex-1 py-12">
|
7
7
|
<div class="relative block text-gray-300 h-64 w-full">
|
File without changes
|
@@ -11,7 +11,7 @@
|
|
11
11
|
translation_key = 'avo.table_view'
|
12
12
|
end
|
13
13
|
%>
|
14
|
-
<%= a_link params.permit!.merge(view_type: new_view_type), color: :blue, 'data-turbo-frame': turbo_frame, title: t('avo.switch_to_view',
|
15
|
-
<%= svg new_icon %> <%= t
|
14
|
+
<%= a_link params.permit!.merge(view_type: new_view_type), color: :blue, 'data-turbo-frame': turbo_frame, title: t('avo.switch_to_view', view_type: new_view_type), 'data-tippy': 'tooltip' do %>
|
15
|
+
<%= svg new_icon %> <%= t translation_key, item: @resource.model_class.model_name.human.downcase %>
|
16
16
|
<% end %>
|
17
17
|
<% end %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
} do |form| %>
|
7
7
|
<%= render Avo::ModalComponent.new do |c| %>
|
8
8
|
<% c.with :heading do %>
|
9
|
-
<%= t
|
9
|
+
<%= t 'avo.choose_item', item: params[:related_name].downcase %>
|
10
10
|
<% end %>
|
11
11
|
|
12
12
|
<div class="flex-1 flex items-center justify-center px-8 text-lg mt-8 mb-12">
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="application-sidebar flex h-full bg-white text-white w-56 z-50 border-r border-gray-300">
|
2
2
|
<div class="flex flex-col w-full">
|
3
3
|
<%= link_to root_path, class: 'logo-placeholder h-16 bg-white p-2 flex justify-center' do %>
|
4
|
-
<%=
|
4
|
+
<%= render partial: "avo/partials/logo" %>
|
5
5
|
<% end %>
|
6
6
|
|
7
7
|
<div class="flex-1 flex flex-col justify-between">
|
@@ -10,9 +10,18 @@
|
|
10
10
|
<%= render Avo::NavigationHeadingComponent.new label: t('avo.resources') %>
|
11
11
|
|
12
12
|
<div class="w-full">
|
13
|
-
<% Avo::App.
|
13
|
+
<% Avo::App.resources_navigation(_current_user).each do |resource| %>
|
14
14
|
<%= render Avo::NavigationLinkComponent.new label: resource.name.pluralize.humanize, path: resources_path(resource.model_class) %>
|
15
15
|
<% end %>
|
16
|
+
|
17
|
+
<% sidebar_partials = Avo::App.get_sidebar_partials %>
|
18
|
+
<% if sidebar_partials.present? %>
|
19
|
+
<%= render Avo::NavigationHeadingComponent.new label: t('avo.tools') %>
|
20
|
+
|
21
|
+
<% sidebar_partials.each do |partial| %>
|
22
|
+
<%= render partial: "/avo/sidebar/items/#{partial}" %>
|
23
|
+
<% end %>
|
24
|
+
<% end %>
|
16
25
|
</div>
|
17
26
|
|
18
27
|
</div>
|
@@ -20,7 +20,7 @@
|
|
20
20
|
<div class="flex-1 flex flex-col h-full overflow-auto">
|
21
21
|
<div class="relative bg-white p-2 shadow-md h-16 w-full flex flex-shrink-0 items-center z-50" v-if="layout !== 'blank'">
|
22
22
|
<div class="ml-6">
|
23
|
-
<%=
|
23
|
+
<%= render partial: "avo/partials/header" %>
|
24
24
|
</div>
|
25
25
|
<div class="flex-1 flex justify-center">
|
26
26
|
<div class="w-64">
|
@@ -31,7 +31,7 @@
|
|
31
31
|
|
32
32
|
<div class="content p-8 flex-1 flex flex-col justify-between items-stretch <%= @container_classes %>">
|
33
33
|
<%= yield %>
|
34
|
-
<%=
|
34
|
+
<%= render partial: "avo/partials/footer" %>
|
35
35
|
</div>
|
36
36
|
</div>
|
37
37
|
</div>
|
@@ -44,6 +44,6 @@
|
|
44
44
|
<% end %>
|
45
45
|
</div>
|
46
46
|
|
47
|
-
<%=
|
47
|
+
<%= render partial: "avo/partials/footer" %>
|
48
48
|
</body>
|
49
49
|
</html>
|
data/config/webpacker.yml
CHANGED
@@ -5,21 +5,32 @@ default: &default
|
|
5
5
|
source_entry_path: entrypoints
|
6
6
|
public_root_path: public
|
7
7
|
cache_path: tmp/cache/webpacker
|
8
|
+
check_yarn_integrity: false
|
8
9
|
# use a different sub-folder name
|
9
10
|
public_output_path: avo-packs
|
10
11
|
webpack_compile_output: true
|
12
|
+
extract_css: true
|
11
13
|
|
12
14
|
# Additional paths webpack should lookup modules
|
13
15
|
# ['app/assets', 'engine/foo/app/assets']
|
14
|
-
|
16
|
+
additional_paths_paths: []
|
15
17
|
|
16
18
|
# Reload manifest.json on all requests so we reload latest compiled packs
|
17
19
|
cache_manifest: false
|
18
20
|
|
21
|
+
# We override the development env. when packed.
|
22
|
+
# Avo needs to be packed and compiled for when the dev uses it in his development env.
|
19
23
|
development:
|
20
24
|
<<: *default
|
25
|
+
|
26
|
+
# Production depends on precompilation of packs prior to booting for performance.
|
21
27
|
compile: true
|
22
28
|
|
29
|
+
# Cache manifest.json for performance
|
30
|
+
cache_manifest: true
|
31
|
+
|
32
|
+
# Even though Avo does not use the dev_server when packed we still need to add the info here.
|
33
|
+
# The packed version of Avo will pick up the parent's app information.
|
23
34
|
# Reference: https://webpack.js.org/configuration/dev-server/
|
24
35
|
dev_server:
|
25
36
|
https: false
|
data/lib/avo/app.rb
CHANGED
@@ -129,12 +129,25 @@ module Avo
|
|
129
129
|
.sort_by { |r| r.name }
|
130
130
|
end
|
131
131
|
|
132
|
-
def
|
132
|
+
def resources_navigation(user = nil)
|
133
133
|
get_available_resources(user).select do |resource|
|
134
134
|
resource.model_class.present?
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
138
|
+
# Insert any partials that we find in app/views/avo/sidebar/items.
|
139
|
+
def get_sidebar_partials
|
140
|
+
Dir.glob(Rails.root.join("app", "views", "avo", "sidebar", "items", "*.html.erb"))
|
141
|
+
.map do |path|
|
142
|
+
File.basename path
|
143
|
+
end
|
144
|
+
.map do |filename|
|
145
|
+
# remove the leading underscore (_)
|
146
|
+
filename[0] = ""
|
147
|
+
filename
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
138
151
|
def draw_routes
|
139
152
|
# We should eager load all the classes so we find all descendants
|
140
153
|
Rails.application.eager_load!
|
data/lib/avo/base_resource.rb
CHANGED
@@ -260,28 +260,27 @@ module Avo
|
|
260
260
|
end
|
261
261
|
end
|
262
262
|
|
263
|
-
# For :new views we're hydrating the model with the values from the resource's default attribute.
|
264
263
|
# We will not overwrite any attributes that come pre-filled in the model.
|
265
264
|
def hydrate_model_with_default_values
|
266
265
|
default_values = get_fields.select do |field|
|
267
266
|
!field.computed
|
268
267
|
end
|
269
268
|
.map do |field|
|
270
|
-
|
271
|
-
|
269
|
+
id = field.id
|
270
|
+
value = field.value
|
272
271
|
|
273
|
-
|
274
|
-
|
272
|
+
if field.respond_to? :foreign_key
|
273
|
+
id = field.foreign_key.to_sym
|
275
274
|
|
276
|
-
|
275
|
+
reflection = @model._reflections[@params[:via_relation]]
|
277
276
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
277
|
+
if reflection.present? && reflection.foreign_key.present? && field.id.to_s == @params[:via_relation].to_s
|
278
|
+
value = @params[:via_resource_id]
|
279
|
+
end
|
280
|
+
end
|
282
281
|
|
283
|
-
|
284
|
-
|
282
|
+
[id, value]
|
283
|
+
end
|
285
284
|
.to_h
|
286
285
|
.select do |id, value|
|
287
286
|
value.present?
|
data/lib/avo/version.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module Generators
|
5
|
+
module Avo
|
6
|
+
class EjectGenerator < ::Rails::Generators::Base
|
7
|
+
argument :filename, type: :string, required: true
|
8
|
+
|
9
|
+
source_root ::Avo::Engine.root
|
10
|
+
|
11
|
+
namespace "avo:eject"
|
12
|
+
|
13
|
+
TEMPLATES = {
|
14
|
+
sidebar: "app/views/avo/sidebar/_sidebar.html.erb",
|
15
|
+
logo: "app/views/avo/partials/logo.html.erb",
|
16
|
+
header: "app/views/avo/partials/header.html.erb",
|
17
|
+
footer: "app/views/avo/partials/footer.html.erb",
|
18
|
+
scripts: "app/views/avo/partials/scripts.html.erb"
|
19
|
+
}
|
20
|
+
|
21
|
+
def handle
|
22
|
+
if @filename.starts_with?(":")
|
23
|
+
template_id = path_to_sym @filename
|
24
|
+
template_path = TEMPLATES[template_id]
|
25
|
+
|
26
|
+
if path_exists? template_path
|
27
|
+
eject template_path
|
28
|
+
else
|
29
|
+
say("Failed to find the `#{template_id.to_sym}` template.", :yellow)
|
30
|
+
end
|
31
|
+
elsif path_exists? @filename
|
32
|
+
eject @filename
|
33
|
+
else
|
34
|
+
say("Failed to find the `#{@filename}` template.", :yellow)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
no_tasks do
|
39
|
+
def path_to_sym(filename)
|
40
|
+
template_id = filename.dup
|
41
|
+
template_id[0] = ""
|
42
|
+
template_id.to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
def path_exists?(path)
|
46
|
+
path.present? && File.file?(::Avo::Engine.root.join(path))
|
47
|
+
end
|
48
|
+
|
49
|
+
def eject(path)
|
50
|
+
copy_file ::Avo::Engine.root.join(path), ::Rails.root.join(path)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%%= render Avo::NavigationLinkComponent.new label: '<%= human_name %>', path: '/avo/<%= file_name %>' %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="flex flex-col">
|
2
|
+
<%%= panel title: '<%= human_name %>' do |c| %>
|
3
|
+
<%% c.with :tools do %>
|
4
|
+
<div class="text-sm italic">This is the panels tools section.</div>
|
5
|
+
<%% end %>
|
6
|
+
|
7
|
+
<%% c.with :body do %>
|
8
|
+
<div class="flex flex-col justify-between py-6 min-h-24">
|
9
|
+
<div class="px-6 space-y-4">
|
10
|
+
<h3>What a nice new tool 👋</h3>
|
11
|
+
|
12
|
+
<p>
|
13
|
+
You can edit this file here <%= in_code "app/views/avo/tools/#{file_name}.html.erb" %>.
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
For this tool we created the <%= in_code file_name %> method in the <%= in_code "Avo::ToolsController" %>. You may delete it or move it to your own controller.
|
18
|
+
</p>
|
19
|
+
|
20
|
+
<p>
|
21
|
+
A new <%= in_code human_name %> item should have been added to the sidebar. Edit it in <%= in_code "app/views/avo/sidebar/items/_#{file_name}.html.erb" %>
|
22
|
+
</p>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
<%% end %>
|
26
|
+
<%% end %>
|
27
|
+
</div>
|