avo 2.9.2.pre1 → 2.10.3.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.lock +69 -69
- data/README.md +4 -0
- data/app/assets/stylesheets/css/buttons.css +4 -1
- data/app/components/avo/actions_component.rb +6 -2
- data/app/components/avo/base_component.rb +2 -0
- data/app/components/avo/button_component.rb +3 -1
- data/app/components/avo/fields/common/key_value_component.html.erb +2 -2
- data/app/components/avo/fields/common/single_file_viewer_component.rb +1 -1
- data/app/components/avo/fields/country_field/edit_component.html.erb +9 -3
- data/app/components/avo/fields/date_field/edit_component.html.erb +26 -7
- data/app/components/avo/fields/date_field/index_component.html.erb +7 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +7 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/edit_component.rb +5 -0
- data/app/components/avo/fields/file_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/files_field/edit_component.html.erb +1 -0
- data/app/components/avo/fields/select_field/edit_component.html.erb +14 -10
- data/app/components/avo/fields/show_component.rb +1 -1
- data/app/components/avo/index/ordering/button_component.rb +1 -15
- data/app/components/avo/index/resource_controls_component.html.erb +2 -2
- data/app/components/avo/index/resource_controls_component.rb +5 -1
- data/app/components/avo/index/resource_table_component.html.erb +1 -1
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/item_switcher_component.html.erb +19 -0
- data/app/components/avo/item_switcher_component.rb +45 -0
- data/app/components/avo/panel_component.html.erb +23 -24
- data/app/components/avo/panel_component.rb +8 -5
- data/app/components/avo/tab_group_component.html.erb +53 -0
- data/app/components/avo/tab_group_component.rb +51 -0
- data/app/components/avo/tab_switcher_component.html.erb +21 -0
- data/app/components/avo/tab_switcher_component.rb +86 -0
- data/app/components/avo/views/resource_edit_component.html.erb +34 -56
- data/app/components/avo/views/resource_edit_component.rb +11 -1
- data/app/components/avo/views/resource_index_component.html.erb +2 -2
- data/app/components/avo/views/resource_index_component.rb +3 -3
- data/app/components/avo/views/resource_show_component.html.erb +58 -89
- data/app/components/avo/views/resource_show_component.rb +2 -2
- data/app/controllers/avo/actions_controller.rb +1 -1
- data/app/controllers/avo/application_controller.rb +33 -10
- data/app/controllers/avo/base_controller.rb +11 -3
- data/app/controllers/avo/reorder_controller.rb +25 -0
- data/app/helpers/avo/application_helper.rb +6 -6
- data/app/helpers/avo/url_helpers.rb +1 -5
- data/app/javascript/avo.js +5 -1
- data/app/javascript/js/controllers/fields/date_field_controller.js +15 -3
- data/app/javascript/js/controllers/loading_button_controller.js +25 -21
- data/app/javascript/js/controllers/search_controller.js +3 -0
- data/app/javascript/js/controllers/tabs_controller.js +86 -0
- data/app/javascript/js/controllers.js +2 -0
- data/app/views/avo/base/index.html.erb +1 -1
- data/app/views/avo/base/show.html.erb +1 -1
- data/app/views/avo/cards/show.html.erb +1 -1
- data/app/views/avo/debug/index.html.erb +1 -1
- data/app/views/avo/home/_actions.html.erb +1 -1
- data/app/views/avo/home/_dashboards.html.erb +19 -0
- data/app/views/avo/home/_filters.html.erb +1 -1
- data/app/views/avo/home/_resources.html.erb +1 -1
- data/app/views/avo/home/failed_to_load.html.erb +1 -1
- data/app/views/avo/home/index.html.erb +14 -2
- data/app/views/avo/partials/_javascript.html.erb +1 -1
- data/app/views/avo/partials/_tabs_toggle.html.erb +20 -0
- data/app/views/avo/private/design.html.erb +1 -1
- data/config/routes.rb +5 -4
- data/db/factories.rb +1 -0
- data/lib/avo/app.rb +12 -7
- data/lib/avo/base_action.rb +2 -19
- data/lib/avo/base_card.rb +1 -7
- data/lib/avo/base_resource.rb +6 -98
- data/lib/avo/base_resource_tool.rb +3 -1
- data/lib/avo/concerns/has_fields.rb +249 -50
- data/lib/avo/concerns/has_html_attributes.rb +1 -1
- data/lib/avo/concerns/is_resource_item.rb +36 -0
- data/lib/avo/concerns/model_class_constantized.rb +23 -0
- data/lib/avo/configuration.rb +2 -12
- data/lib/avo/dashboards/base_dashboard.rb +1 -1
- data/lib/avo/dsl/field_parser.rb +83 -0
- data/lib/avo/fields/base_field.rb +21 -2
- data/lib/avo/fields/country_field.rb +2 -0
- data/lib/avo/fields/date_field.rb +13 -9
- data/lib/avo/fields/field_extensions/has_include_blank.rb +17 -0
- data/lib/avo/fields/field_extensions/visible_in_different_views.rb +18 -1
- data/lib/avo/fields/file_field.rb +2 -0
- data/lib/avo/fields/files_field.rb +2 -0
- data/lib/avo/fields/has_base_field.rb +20 -1
- data/lib/avo/fields/has_one_field.rb +4 -1
- data/lib/avo/fields/key_value_field.rb +4 -4
- data/lib/avo/fields/select_field.rb +2 -0
- data/lib/avo/grid_collector.rb +6 -3
- data/lib/avo/items_holder.rb +68 -0
- data/lib/avo/licensing/h_q.rb +12 -0
- data/lib/avo/main_panel.rb +3 -0
- data/lib/avo/menu/builder.rb +8 -7
- data/lib/avo/panel.rb +25 -0
- data/lib/avo/panel_builder.rb +23 -0
- data/lib/avo/services/uri_service.rb +75 -0
- data/lib/avo/tab.rb +78 -0
- data/lib/avo/tab_builder.rb +25 -0
- data/lib/avo/tab_group.rb +40 -0
- data/lib/avo/tab_group_builder.rb +43 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +1 -0
- data/lib/generators/avo/action_generator.rb +3 -2
- data/lib/generators/avo/base_generator.rb +14 -0
- data/lib/generators/avo/card/chartkick_generator.rb +18 -0
- data/lib/generators/avo/card/metric_generator.rb +18 -0
- data/lib/generators/avo/card/partial_generator.rb +19 -0
- data/lib/generators/avo/controller_generator.rb +9 -3
- data/lib/generators/avo/dashboard_generator.rb +2 -2
- data/lib/generators/avo/eject_generator.rb +2 -3
- data/lib/generators/avo/field_generator.rb +2 -2
- data/lib/generators/avo/filter_generator.rb +3 -2
- data/lib/generators/avo/install_generator.rb +2 -2
- data/lib/generators/avo/locales_generator.rb +2 -2
- data/lib/generators/avo/named_base_generator.rb +14 -0
- data/lib/generators/avo/resource_generator.rb +2 -2
- data/lib/generators/avo/resource_tool_generator.rb +4 -4
- data/lib/generators/avo/templates/locales/avo.fr.yml +115 -0
- data/lib/generators/avo/templates/resource/controller.tt +2 -0
- data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
- data/lib/generators/avo/templates/tool/view.tt +1 -1
- data/lib/generators/avo/tool_generator.rb +4 -4
- data/lib/generators/avo/version_generator.rb +23 -0
- data/public/avo-assets/avo.css +31 -3
- data/public/avo-assets/avo.js +72 -72
- data/public/avo-assets/avo.js.map +3 -3
- metadata +32 -16
- data/app/assets/builds/action_cable.js +0 -2
- data/app/assets/builds/action_cable.js.map +0 -7
- data/app/assets/builds/application.js +0 -2
- data/app/assets/builds/application.js.map +0 -7
- data/app/assets/builds/avo.css +0 -9028
- data/app/assets/builds/avo.js +0 -512
- data/app/assets/builds/avo.js.map +0 -7
- data/app/assets/builds/avo_custom.js +0 -6
- data/app/assets/builds/avo_custom.js.map +0 -7
- data/lib/avo/concerns/has_tools.rb +0 -47
- data/lib/avo/fields/currency_field.rb +0 -15
- data/lib/generators/avo/chartkick_card_generator.rb +0 -16
- data/lib/generators/avo/metric_card_generator.rb +0 -16
- data/lib/generators/avo/partial_card_generator.rb +0 -17
@@ -7,13 +7,20 @@ module Avo
|
|
7
7
|
attr_accessor :show_on_new
|
8
8
|
attr_accessor :show_on_edit
|
9
9
|
|
10
|
-
def initialize(id, **args, &block)
|
10
|
+
def initialize(id = nil, **args, &block)
|
11
11
|
@show_on_index = @show_on_index.nil? ? true : @show_on_index
|
12
12
|
@show_on_show = @show_on_show.nil? ? true : @show_on_show
|
13
13
|
@show_on_new = @show_on_new.nil? ? true : @show_on_new
|
14
14
|
@show_on_edit = @show_on_edit.nil? ? true : @show_on_edit
|
15
15
|
end
|
16
16
|
|
17
|
+
# Validates if the field is visible on certain view
|
18
|
+
def visible_on?(view)
|
19
|
+
raise "No view specified on visibility check." if view.blank?
|
20
|
+
|
21
|
+
send :"show_on_#{view.to_s}"
|
22
|
+
end
|
23
|
+
|
17
24
|
def show_on(*where)
|
18
25
|
return show_on_all if where.include? :all
|
19
26
|
|
@@ -44,6 +51,16 @@ module Avo
|
|
44
51
|
end
|
45
52
|
end
|
46
53
|
|
54
|
+
# When submitting the form on creation, the new page will be create but we don't have a visibility marker for create so we'll default to new
|
55
|
+
def show_on_create
|
56
|
+
show_on_new
|
57
|
+
end
|
58
|
+
|
59
|
+
# When submitting the form on update, the new page will be create but we don't have a visibility marker for update so we'll default to edit
|
60
|
+
def show_on_update
|
61
|
+
show_on_edit
|
62
|
+
end
|
63
|
+
|
47
64
|
private
|
48
65
|
|
49
66
|
def show_on_view(view)
|
@@ -6,6 +6,7 @@ module Avo
|
|
6
6
|
attr_accessor :is_image
|
7
7
|
attr_accessor :is_audio
|
8
8
|
attr_accessor :direct_upload
|
9
|
+
attr_accessor :accept
|
9
10
|
|
10
11
|
def initialize(id, **args, &block)
|
11
12
|
super(id, **args, &block)
|
@@ -15,6 +16,7 @@ module Avo
|
|
15
16
|
@is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
|
16
17
|
@is_audio = args[:is_audio].present? ? args[:is_audio] : false
|
17
18
|
@direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
|
19
|
+
@accept = args[:accept].present? ? args[:accept] : nil
|
18
20
|
end
|
19
21
|
|
20
22
|
def path
|
@@ -4,6 +4,7 @@ module Avo
|
|
4
4
|
attr_accessor :is_audio
|
5
5
|
attr_accessor :is_image
|
6
6
|
attr_accessor :direct_upload
|
7
|
+
attr_accessor :accept
|
7
8
|
|
8
9
|
def initialize(id, **args, &block)
|
9
10
|
super(id, **args, &block)
|
@@ -11,6 +12,7 @@ module Avo
|
|
11
12
|
@is_audio = args[:is_audio].present? ? args[:is_audio] : false
|
12
13
|
@is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
|
13
14
|
@direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
|
15
|
+
@accept = args[:accept].present? ? args[:accept] : nil
|
14
16
|
end
|
15
17
|
|
16
18
|
def view_component_name
|
@@ -29,7 +29,10 @@ module Avo
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def frame_url
|
32
|
-
|
32
|
+
Avo::Services::URIService.parse(@resource.record_path)
|
33
|
+
.append_path(id.to_s)
|
34
|
+
.append_query(turbo_frame: turbo_frame.to_s)
|
35
|
+
.to_s
|
33
36
|
end
|
34
37
|
|
35
38
|
# The value
|
@@ -59,6 +62,22 @@ module Avo
|
|
59
62
|
def placeholder
|
60
63
|
@placeholder || I18n.t("avo.choose_an_option")
|
61
64
|
end
|
65
|
+
|
66
|
+
def has_own_panel?
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def visible_in_reflection?
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
# Adds the view override component
|
75
|
+
# has_one, has_many, has_and_belongs_to_many fields don't have edit views
|
76
|
+
def component_for_view(view = :index)
|
77
|
+
view = :show if view.in? [:new, :create, :update, :edit]
|
78
|
+
|
79
|
+
super view
|
80
|
+
end
|
62
81
|
end
|
63
82
|
end
|
64
83
|
end
|
@@ -22,7 +22,10 @@ module Avo
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def frame_url
|
25
|
-
|
25
|
+
Avo::Services::URIService.parse(@resource.record_path)
|
26
|
+
.append_paths(id, value.id)
|
27
|
+
.append_query(turbo_frame: turbo_frame)
|
28
|
+
.to_s
|
26
29
|
end
|
27
30
|
|
28
31
|
def fill_field(model, key, value, params)
|
@@ -64,10 +64,10 @@ module Avo
|
|
64
64
|
|
65
65
|
def options
|
66
66
|
{
|
67
|
-
key_label:
|
68
|
-
value_label:
|
69
|
-
action_text:
|
70
|
-
delete_text:
|
67
|
+
key_label: key_label,
|
68
|
+
value_label: value_label,
|
69
|
+
action_text: action_text,
|
70
|
+
delete_text: delete_text,
|
71
71
|
disable_editing_keys: @disable_editing_keys,
|
72
72
|
disable_adding_rows: @disable_adding_rows,
|
73
73
|
disable_deleting_rows: @disable_deleting_rows
|
data/lib/avo/grid_collector.rb
CHANGED
@@ -13,15 +13,18 @@ module Avo
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def cover(field_name, as:, **args, &block)
|
16
|
-
|
16
|
+
field_parser = Avo::Dsl::FieldParser.new(id: field_name, as: as, order_index: items_index, **args, &block).parse
|
17
|
+
self.cover_field = field_parser.instance if field_parser.valid?
|
17
18
|
end
|
18
19
|
|
19
20
|
def title(field_name, as:, **args, &block)
|
20
|
-
|
21
|
+
field_parser = Avo::Dsl::FieldParser.new(id: field_name, as: as, order_index: items_index, **args, &block).parse
|
22
|
+
self.title_field = field_parser.instance if field_parser.valid?
|
21
23
|
end
|
22
24
|
|
23
25
|
def body(field_name, as:, **args, &block)
|
24
|
-
|
26
|
+
field_parser = Avo::Dsl::FieldParser.new(id: field_name, as: as, order_index: items_index, **args, &block).parse
|
27
|
+
self.body_field = field_parser.instance if field_parser.valid?
|
25
28
|
end
|
26
29
|
|
27
30
|
def hydrate(model:, view:, resource:)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Avo
|
2
|
+
class ItemsHolder
|
3
|
+
attr_reader :tools
|
4
|
+
attr_accessor :items
|
5
|
+
attr_accessor :invalid_fields
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@items = []
|
9
|
+
@items_index = 0
|
10
|
+
@invalid_fields = []
|
11
|
+
end
|
12
|
+
|
13
|
+
# Adds a field to the bag
|
14
|
+
def field(field_name, **args, &block)
|
15
|
+
field_parser = Avo::Dsl::FieldParser.new(id: field_name, order_index: @items_index, **args, &block).parse
|
16
|
+
|
17
|
+
if field_parser.invalid?
|
18
|
+
as = args.fetch(:as, nil)
|
19
|
+
|
20
|
+
# End execution ehre and add the field to the invalid_fileds payload so we know to wanr the developer about that.
|
21
|
+
# @todo: Make sure this warning is still active
|
22
|
+
return add_invalid_field({
|
23
|
+
name: field_name,
|
24
|
+
as: as,
|
25
|
+
# resource: resource_class.name,
|
26
|
+
message: "There's an invalid field configuration for this resource. <br/> <code class='px-1 py-px rounded bg-red-600'>field :#{field_name}, as: #{as}</code>"
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
add_item field_parser.instance
|
31
|
+
end
|
32
|
+
|
33
|
+
def tabs(instance)
|
34
|
+
add_item instance
|
35
|
+
end
|
36
|
+
|
37
|
+
def tab(name, **args, &block)
|
38
|
+
add_item Avo::TabBuilder.parse_block(name: name, **args, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def tool(klass, **args)
|
42
|
+
instance = klass.new(**args)
|
43
|
+
add_item instance
|
44
|
+
end
|
45
|
+
|
46
|
+
def panel(panel_name = nil, **args, &block)
|
47
|
+
panel = Avo::PanelBuilder.parse_block(name: panel_name, **args, &block)
|
48
|
+
|
49
|
+
add_item panel
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_item(instance)
|
53
|
+
@items << instance
|
54
|
+
|
55
|
+
increment_order_index
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def add_invalid_field(payload)
|
61
|
+
@invalid_fields << payload
|
62
|
+
end
|
63
|
+
|
64
|
+
def increment_order_index
|
65
|
+
@items_index += 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/avo/licensing/h_q.rb
CHANGED
@@ -98,6 +98,7 @@ module Avo
|
|
98
98
|
**other_metadata(:filters),
|
99
99
|
main_menu_present: Avo.configuration.main_menu.present?,
|
100
100
|
profile_menu_present: Avo.configuration.profile_menu.present?,
|
101
|
+
**config_metadata
|
101
102
|
}
|
102
103
|
rescue
|
103
104
|
{}
|
@@ -120,6 +121,8 @@ module Avo
|
|
120
121
|
cache_and_return_error "HTTP connection reset error.", exception.message
|
121
122
|
rescue Errno::ECONNREFUSED => exception
|
122
123
|
cache_and_return_error "HTTP connection refused error.", exception.message
|
124
|
+
rescue OpenSSL::SSL::SSLError => exception
|
125
|
+
cache_and_return_error "OpenSSL error.", exception.message
|
123
126
|
rescue HTTParty::Error => exception
|
124
127
|
cache_and_return_error "HTTP client error.", exception.message
|
125
128
|
rescue Net::OpenTimeout => exception
|
@@ -178,6 +181,15 @@ module Avo
|
|
178
181
|
}
|
179
182
|
end
|
180
183
|
|
184
|
+
def config_metadata
|
185
|
+
{
|
186
|
+
config: {
|
187
|
+
root_path: Avo.configuration.root_path,
|
188
|
+
app_name: Avo.configuration.app_name
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
181
193
|
def cache_and_return_error(error, exception_message = "")
|
182
194
|
cache_response response: {error: error, exception_message: exception_message}.stringify_keys, time: 5.minutes.to_i
|
183
195
|
end
|
data/lib/avo/menu/builder.rb
CHANGED
@@ -5,6 +5,13 @@ class Avo::Menu::Builder
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
delegate :context, to: ::Avo::App
|
9
|
+
delegate :current_user, to: ::Avo::App
|
10
|
+
delegate :params, to: ::Avo::App
|
11
|
+
delegate :request, to: ::Avo::App
|
12
|
+
delegate :root_path, to: ::Avo::App
|
13
|
+
delegate :view_context, to: ::Avo::App
|
14
|
+
|
8
15
|
def initialize(name: nil, items: [])
|
9
16
|
@menu = Avo::Menu::Menu.new
|
10
17
|
|
@@ -60,7 +67,7 @@ class Avo::Menu::Builder
|
|
60
67
|
# Add all the tools
|
61
68
|
def all_tools(**args)
|
62
69
|
Avo::App.tools_for_navigation.each do |tool|
|
63
|
-
link tool.humanize, path:
|
70
|
+
link tool.humanize, path: root_path(paths: [tool])
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
@@ -68,10 +75,4 @@ class Avo::Menu::Builder
|
|
68
75
|
def build
|
69
76
|
@menu
|
70
77
|
end
|
71
|
-
|
72
|
-
protected
|
73
|
-
|
74
|
-
def root_path
|
75
|
-
Avo::App.root_path
|
76
|
-
end
|
77
78
|
end
|
data/lib/avo/panel.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Avo::Panel
|
2
|
+
include Avo::Concerns::IsResourceItem
|
3
|
+
|
4
|
+
class_attribute :item_type, default: :panel
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :description
|
8
|
+
attr_accessor :items_holder
|
9
|
+
|
10
|
+
delegate :items, :add_item, to: :items_holder
|
11
|
+
|
12
|
+
def initialize(name: nil, description: nil)
|
13
|
+
@name = name
|
14
|
+
@description = description
|
15
|
+
@items_holder = Avo::ItemsHolder.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_item(item)
|
19
|
+
@items << item
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_items?
|
23
|
+
@items.present?
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Avo::PanelBuilder
|
2
|
+
class << self
|
3
|
+
def parse_block(**args, &block)
|
4
|
+
Docile.dsl_eval(new(**args), &block).build
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
delegate :field, to: :items_holder
|
9
|
+
delegate :items, to: :items_holder
|
10
|
+
|
11
|
+
attr_reader :items_holder
|
12
|
+
|
13
|
+
def initialize(name: nil, **args)
|
14
|
+
@panel = Avo::Panel.new(name: name, **args)
|
15
|
+
@items_holder = Avo::ItemsHolder.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetch the tab
|
19
|
+
def build
|
20
|
+
@panel.items_holder = @items_holder
|
21
|
+
@panel
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Avo
|
2
|
+
module Services
|
3
|
+
class URIService
|
4
|
+
class << self
|
5
|
+
def parse(path)
|
6
|
+
self.new path
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :uri
|
11
|
+
|
12
|
+
def initialize(path = '')
|
13
|
+
@uri = Addressable::URI.parse(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def append_paths(*paths)
|
21
|
+
paths = Array.wrap(paths).flatten
|
22
|
+
|
23
|
+
return self if paths.blank?
|
24
|
+
|
25
|
+
# Add the intermediary forward slash
|
26
|
+
@uri.path = @uri.path.concat("/") unless @uri.path.ends_with? "/"
|
27
|
+
|
28
|
+
# Add the paths to the URI
|
29
|
+
@uri.merge!(path: @uri.path.concat(join_paths(paths)))
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
alias_method :append_path, :append_paths
|
34
|
+
|
35
|
+
def append_query(params)
|
36
|
+
params = if params.is_a? Hash
|
37
|
+
params.map do |key, value|
|
38
|
+
"#{key}=#{value}"
|
39
|
+
end
|
40
|
+
else
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
return self if params.blank?
|
45
|
+
|
46
|
+
# Add the query params to the URI
|
47
|
+
@uri.merge!(query: [@uri.query, *params].compact.join("&"))
|
48
|
+
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
@uri.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def join_paths(paths)
|
59
|
+
paths.map do |path|
|
60
|
+
sanitize_path path
|
61
|
+
end
|
62
|
+
.join("/")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Removes the forward slash if it's present at the start of the path
|
66
|
+
def sanitize_path(path)
|
67
|
+
if path.to_s.starts_with? '/'
|
68
|
+
path = path[1..-1]
|
69
|
+
end
|
70
|
+
|
71
|
+
path
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/avo/tab.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class Avo::Tab
|
2
|
+
include Avo::Concerns::IsResourceItem
|
3
|
+
include Avo::Fields::FieldExtensions::VisibleInDifferentViews
|
4
|
+
|
5
|
+
class_attribute :item_type, default: :tab
|
6
|
+
delegate :items, :add_item, to: :items_holder
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
attr_reader :view
|
10
|
+
attr_accessor :description
|
11
|
+
attr_accessor :items_holder
|
12
|
+
attr_accessor :holds_one_field
|
13
|
+
|
14
|
+
def initialize(name: nil, description: nil, view: nil, holds_one_field: false, **args)
|
15
|
+
# Initialize the visibility markers
|
16
|
+
super
|
17
|
+
|
18
|
+
@name = name
|
19
|
+
@description = description
|
20
|
+
@holds_one_field = holds_one_field
|
21
|
+
@items_holder = Avo::ItemsHolder.new
|
22
|
+
@view = view
|
23
|
+
|
24
|
+
show_on args[:show_on] if args[:show_on].present?
|
25
|
+
hide_on args[:hide_on] if args[:hide_on].present?
|
26
|
+
only_on args[:only_on] if args[:only_on].present?
|
27
|
+
except_on args[:except_on] if args[:except_on].present?
|
28
|
+
end
|
29
|
+
|
30
|
+
def hydrate(view: nil)
|
31
|
+
@view = view
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def turbo_frame_id(parent: nil)
|
37
|
+
id = "#{Avo::Tab.to_s.parameterize} #{name}".parameterize
|
38
|
+
|
39
|
+
return id if parent.nil?
|
40
|
+
|
41
|
+
"#{parent.turbo_frame_id} #{id}".parameterize
|
42
|
+
end
|
43
|
+
|
44
|
+
def empty?
|
45
|
+
visible_items.blank?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Checks for visibility on itself or on theone field it holds
|
49
|
+
def visible_on?(view)
|
50
|
+
if holds_one_field
|
51
|
+
super(view) && items.first.visible_on?(view)
|
52
|
+
else
|
53
|
+
super(view)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def items
|
58
|
+
if self.items_holder.present?
|
59
|
+
self.items_holder.items
|
60
|
+
else
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def visible_items
|
66
|
+
items.map do |item|
|
67
|
+
if item.is_field?
|
68
|
+
visible = item.visible_on?(view)
|
69
|
+
# Remove the fields that shouldn't be visible in this view
|
70
|
+
# eg: has_many fields on edit
|
71
|
+
item = nil unless visible
|
72
|
+
end
|
73
|
+
|
74
|
+
item
|
75
|
+
end
|
76
|
+
.compact
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Avo::TabBuilder
|
2
|
+
class << self
|
3
|
+
def parse_block(**args, &block)
|
4
|
+
Docile.dsl_eval(new(**args), &block).build
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :items_holder
|
9
|
+
|
10
|
+
delegate :field, to: :items_holder
|
11
|
+
delegate :tool, to: :items_holder
|
12
|
+
delegate :panel, to: :items_holder
|
13
|
+
delegate :items, to: :items_holder
|
14
|
+
|
15
|
+
def initialize(name: nil, **args)
|
16
|
+
@tab = Avo::Tab.new(name: name, **args)
|
17
|
+
@items_holder = Avo::ItemsHolder.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Fetch the tab
|
21
|
+
def build
|
22
|
+
@tab.items_holder = @items_holder
|
23
|
+
@tab
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Avo::TabGroup
|
2
|
+
include Avo::Concerns::HasFields
|
3
|
+
include Avo::Concerns::IsResourceItem
|
4
|
+
|
5
|
+
class_attribute :item_type, default: :tab_group
|
6
|
+
|
7
|
+
attr_reader :view
|
8
|
+
attr_accessor :index
|
9
|
+
attr_accessor :items_holder
|
10
|
+
|
11
|
+
def initialize(index: 0, view: nil)
|
12
|
+
@index = index
|
13
|
+
@items_holder = Avo::ItemsHolder.new
|
14
|
+
@view = view
|
15
|
+
end
|
16
|
+
|
17
|
+
def hydrate(view: nil)
|
18
|
+
@view = view
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def visible_items
|
24
|
+
items.map do |item|
|
25
|
+
item.hydrate view: view
|
26
|
+
end
|
27
|
+
.select do |item|
|
28
|
+
# Remove items hidden in this view
|
29
|
+
item.visible_on? view
|
30
|
+
end
|
31
|
+
.select do |item|
|
32
|
+
# Remove empty items
|
33
|
+
!item.empty?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def turbo_frame_id
|
38
|
+
"#{Avo::TabGroup.to_s.parameterize} #{index}".parameterize
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Avo::TabGroupBuilder
|
2
|
+
class << self
|
3
|
+
def parse_block(&block)
|
4
|
+
Docile.dsl_eval(new, &block).build
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :items_holder
|
9
|
+
|
10
|
+
delegate :tab, to: :items_holder
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@group = Avo::TabGroup.new
|
14
|
+
@items_holder = Avo::ItemsHolder.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def field(field_name, **args, &block)
|
18
|
+
parsed = Avo::Dsl::FieldParser.new(id: field_name, order_index: @items_index, **args, &block).parse
|
19
|
+
field_instance = parsed.instance
|
20
|
+
|
21
|
+
name = field_instance.name
|
22
|
+
tab = Avo::Tab.new name: name
|
23
|
+
|
24
|
+
if field_instance.has_own_panel?
|
25
|
+
tab.items_holder.add_item parsed.instance
|
26
|
+
tab.holds_one_field = true
|
27
|
+
else
|
28
|
+
# If the field is not in a panel, create one and add it
|
29
|
+
panel = Avo::Panel.new name: name
|
30
|
+
panel.items_holder.add_item parsed.instance
|
31
|
+
# Add that panel to the bag
|
32
|
+
tab.items_holder.add_item panel
|
33
|
+
end
|
34
|
+
|
35
|
+
@items_holder.tabs tab
|
36
|
+
end
|
37
|
+
|
38
|
+
# Fetch the tab
|
39
|
+
def build
|
40
|
+
@group.items_holder = @items_holder
|
41
|
+
@group
|
42
|
+
end
|
43
|
+
end
|
data/lib/avo/version.rb
CHANGED
data/lib/avo.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
require_relative "named_base_generator"
|
2
2
|
|
3
3
|
module Generators
|
4
4
|
module Avo
|
5
|
-
class ActionGenerator <
|
5
|
+
class ActionGenerator < NamedBaseGenerator
|
6
6
|
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
7
8
|
class_option :standalone, type: :boolean
|
8
9
|
|
9
10
|
namespace "avo:action"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "../named_base_generator"
|
2
|
+
|
3
|
+
module Generators
|
4
|
+
module Avo
|
5
|
+
module Card
|
6
|
+
class ChartkickGenerator < Generators::Avo::NamedBaseGenerator
|
7
|
+
source_root File.expand_path("../templates", __dir__)
|
8
|
+
|
9
|
+
namespace "avo:card:chartkick"
|
10
|
+
desc "Add a chartkick card for your Avo dashboard."
|
11
|
+
|
12
|
+
def handle
|
13
|
+
template "cards/chartkick_card_sample.tt", "app/avo/cards/#{name.underscore}.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|