avo 2.16.1.pre.1.nativefields → 2.17.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 +4 -4
- data/Gemfile +4 -2
- data/Gemfile.lock +3 -1
- data/README.md +1 -1
- data/app/assets/config/avo_manifest.js +1 -0
- data/app/assets/svgs/placeholder.svg +1 -0
- data/app/components/avo/actions_component.html.erb +3 -3
- data/app/components/avo/base_component.rb +7 -4
- data/app/components/avo/field_wrapper_component.html.erb +8 -10
- data/app/components/avo/field_wrapper_component.rb +14 -12
- data/app/components/avo/fields/badge_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +9 -3
- data/app/components/avo/fields/belongs_to_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/show_component.rb +1 -1
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/boolean_group_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/code_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/common/heading_component.html.erb +5 -4
- data/app/components/avo/fields/common/heading_component.rb +6 -1
- data/app/components/avo/fields/country_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/edit_component.rb +6 -4
- data/app/components/avo/fields/external_image_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/edit_component.html.erb +2 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/edit_component.html.erb +2 -1
- data/app/components/avo/fields/files_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/gravatar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/heading_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/heading_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/index_component.rb +11 -2
- data/app/components/avo/fields/number_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/show_component.rb +7 -1
- data/app/components/avo/fields/status_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/edit_component.html.erb +3 -1
- data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +1 -1
- data/app/components/avo/filters_component.html.erb +2 -2
- data/app/components/avo/index/grid_cover_empty_state_component.html.erb +1 -1
- data/app/components/avo/index/grid_item_component.html.erb +15 -13
- data/app/components/avo/index/grid_item_component.rb +1 -1
- data/app/components/avo/index/ordering/buttons_component.html.erb +1 -1
- data/app/components/avo/index/resource_controls_component.rb +2 -2
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/panel_component.html.erb +11 -2
- data/app/components/avo/panel_component.rb +1 -0
- data/app/components/avo/resource_component.rb +18 -0
- data/app/components/avo/resource_sidebar_component.html.erb +19 -0
- data/app/components/avo/resource_sidebar_component.rb +26 -0
- data/app/components/avo/sidebar_profile_component.html.erb +1 -1
- data/app/components/avo/tab_switcher_component.html.erb +2 -2
- data/app/components/avo/views/resource_edit_component.html.erb +31 -25
- data/app/components/avo/views/resource_edit_component.rb +1 -1
- data/app/components/avo/views/resource_show_component.html.erb +8 -2
- data/app/components/avo/views/resource_show_component.rb +1 -1
- data/app/controllers/avo/actions_controller.rb +10 -2
- data/app/controllers/avo/application_controller.rb +4 -2
- data/app/controllers/avo/associations_controller.rb +10 -5
- data/app/controllers/avo/attachments_controller.rb +2 -1
- data/app/controllers/avo/base_controller.rb +6 -4
- data/app/controllers/avo/search_controller.rb +13 -4
- data/app/helpers/avo/application_helper.rb +3 -3
- data/app/helpers/avo/resources_helper.rb +2 -2
- data/app/javascript/avo.base.js +3 -1
- data/app/javascript/js/controllers/action_controller.js +1 -4
- data/app/javascript/js/controllers/actions_picker_controller.js +8 -9
- data/app/javascript/js/controllers/tabs_controller.js +14 -27
- data/app/views/avo/actions/show.html.erb +2 -2
- data/app/views/avo/home/failed_to_load.html.erb +3 -2
- data/config/brakeman.ignore +40 -0
- data/db/factories.rb +20 -0
- data/lib/avo/base_resource.rb +26 -0
- data/lib/avo/concerns/fetches_things.rb +1 -1
- data/lib/avo/concerns/has_fields.rb +22 -0
- data/lib/avo/concerns/is_resource_item.rb +4 -0
- data/lib/avo/configuration/branding.rb +9 -1
- data/lib/avo/fields/belongs_to_field.rb +3 -0
- data/lib/avo/fields/heading_field.rb +15 -0
- data/lib/avo/items_holder.rb +4 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/menu/builder.rb +1 -1
- data/lib/avo/menu/menu.rb +0 -2
- data/lib/avo/reloader.rb +27 -26
- data/lib/avo/services/encryption_service.rb +1 -1
- data/lib/avo/sidebar.rb +60 -0
- data/lib/avo/sidebar_builder.rb +24 -0
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/templates/field/components/index_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +2 -1
- data/lib/generators/avo/templates/locales/avo.en.yml +0 -1
- data/lib/generators/avo/templates/locales/{avo.nb-NO.yml → avo.nb.yml} +35 -10
- data/lib/generators/avo/templates/locales/avo.nn.yml +118 -0
- data/lib/generators/avo/templates/locales/avo.tr.yml +119 -0
- data/public/avo-assets/avo.base.css +57 -75
- data/public/avo-assets/avo.base.js +63 -63
- data/public/avo-assets/avo.base.js.map +3 -3
- metadata +13 -7
- data/app/views/avo/home/failed_to_load.html copy.erb +0 -23
- data/config/master.key +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { castBoolean } from '../helpers/cast_boolean'
|
|
2
1
|
import { Controller } from '@hotwired/stimulus'
|
|
2
|
+
import { castBoolean } from '../helpers/cast_boolean'
|
|
3
3
|
|
|
4
4
|
export default class extends Controller {
|
|
5
5
|
static targets = ['controllerDiv', 'resourceIds', 'form', 'selectedAllQuery']
|
|
@@ -7,8 +7,6 @@ export default class extends Controller {
|
|
|
7
7
|
connect() {
|
|
8
8
|
this.resourceIdsTarget.value = this.resourceIds
|
|
9
9
|
|
|
10
|
-
console.log('something')
|
|
11
|
-
|
|
12
10
|
// This value is picked up from the DOM so we check true/false as strings
|
|
13
11
|
if (this.selectionOptions.itemSelectAllSelectedAllValue === 'true') {
|
|
14
12
|
this.selectedAllQueryTarget.value = this.selectionOptions.itemSelectAllSelectedAllQueryValue
|
|
@@ -43,6 +41,5 @@ export default class extends Controller {
|
|
|
43
41
|
} catch (error) {
|
|
44
42
|
return []
|
|
45
43
|
}
|
|
46
|
-
|
|
47
44
|
}
|
|
48
45
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AttributeObserver } from '@stimulus/mutation-observers'
|
|
2
1
|
import { Controller } from '@hotwired/stimulus'
|
|
3
2
|
|
|
4
3
|
export default class extends Controller {
|
|
@@ -12,6 +11,10 @@ export default class extends Controller {
|
|
|
12
11
|
return this.target.dataset.disabled === 'true'
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
get actionsShowTurboFrame() {
|
|
15
|
+
return document.querySelector('turbo-frame#actions_show')
|
|
16
|
+
}
|
|
17
|
+
|
|
15
18
|
enableTarget() {
|
|
16
19
|
if (this.targetIsDisabled) {
|
|
17
20
|
this.target.classList.remove(...this.disabledClasses)
|
|
@@ -36,13 +39,9 @@ export default class extends Controller {
|
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
this.disableTarget()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (observer) observer.stop()
|
|
44
|
-
},
|
|
45
|
-
})
|
|
46
|
-
observer.start()
|
|
42
|
+
const that = this
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
this.actionsShowTurboFrame.loaded.then(() => that.enableTarget(that.target))
|
|
45
|
+
}, 1)
|
|
47
46
|
}
|
|
48
47
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AttributeObserver } from '@stimulus/mutation-observers'
|
|
2
1
|
import { Controller } from '@hotwired/stimulus'
|
|
3
2
|
import { castBoolean } from '../helpers/cast_boolean'
|
|
4
3
|
|
|
@@ -16,24 +15,22 @@ export default class extends Controller {
|
|
|
16
15
|
)
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
targetTab(id) {
|
|
20
|
-
return this.tabTargets.find((element) => element.dataset.tabsIdParam === id)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
18
|
targetTabPanel(id) {
|
|
24
19
|
return this.tabPanelTargets.find((element) => element.dataset.tabId === id)
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
changeTab(e) {
|
|
22
|
+
async changeTab(e) {
|
|
23
|
+
// Stopping the link execution.
|
|
24
|
+
// We're going to reveal a lazy-loaded frame to fulfill the tab change.
|
|
28
25
|
e.preventDefault()
|
|
29
26
|
|
|
30
27
|
const { params } = e
|
|
31
28
|
const { id } = params
|
|
32
29
|
|
|
33
|
-
this.setTheTargetPanelHeight(id)
|
|
30
|
+
await this.setTheTargetPanelHeight(id)
|
|
34
31
|
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
32
|
+
this.hideAllTabs()
|
|
33
|
+
this.revealTab(id)
|
|
37
34
|
this.markTabLoaded(id)
|
|
38
35
|
|
|
39
36
|
this.activeTabValue = id
|
|
@@ -42,7 +39,7 @@ export default class extends Controller {
|
|
|
42
39
|
/**
|
|
43
40
|
* Sets the target container height to the previous panel height so we don't get jerky tab changes.
|
|
44
41
|
*/
|
|
45
|
-
setTheTargetPanelHeight(id) {
|
|
42
|
+
async setTheTargetPanelHeight(id) {
|
|
46
43
|
// Ignore this on edit.
|
|
47
44
|
// All tabs are loaded beforehand, they have their own height, and the page won't jiggle when the user toggles between them.
|
|
48
45
|
if (this.viewValue === 'edit' || this.viewValue === 'new') {
|
|
@@ -60,31 +57,21 @@ export default class extends Controller {
|
|
|
60
57
|
this.targetTabPanel(id).style.height = `${height}px`
|
|
61
58
|
|
|
62
59
|
// Wait until the panel loaded it's content and then remove the forced height
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// The content is not available in an instant so delay the height reset a bit.
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
this.targetTab(id).style.height = ''
|
|
68
|
-
}, 300)
|
|
69
|
-
if (observer) observer.stop()
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
observer.start()
|
|
60
|
+
await this.targetTabPanel(id).loaded
|
|
61
|
+
this.targetTabPanel(id).style.height = ''
|
|
73
62
|
}
|
|
74
63
|
|
|
64
|
+
// Marking tab as loaded so we know to skip some things the next time the user clicks on it
|
|
75
65
|
markTabLoaded(id) {
|
|
76
66
|
this.targetTabPanel(id).dataset.loaded = true
|
|
77
67
|
}
|
|
78
68
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
element.classList.remove('hidden')
|
|
83
|
-
}
|
|
84
|
-
})
|
|
69
|
+
// We're revealing the new tab that's lazy loaded by Turbo.
|
|
70
|
+
revealTab(id) {
|
|
71
|
+
this.targetTabPanel(id).classList.remove('hidden')
|
|
85
72
|
}
|
|
86
73
|
|
|
87
|
-
|
|
74
|
+
hideAllTabs() {
|
|
88
75
|
this.tabPanelTargets.map((element) => element.classList.add('hidden'))
|
|
89
76
|
}
|
|
90
77
|
}
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
<%= form.hidden_field :avo_resource_ids, value: params[:resource_ids], 'data-action-target': 'resourceIds' %>
|
|
24
24
|
<%= form.hidden_field :avo_selected_query, 'data-action-target': 'selectedAllQuery' %>
|
|
25
25
|
<% if @action.get_fields.present? %>
|
|
26
|
-
<div class="
|
|
26
|
+
<div class="my-4 -mx-6">
|
|
27
27
|
<% @action.get_fields.each_with_index do |field, index| %>
|
|
28
28
|
<%= render field
|
|
29
29
|
.hydrate(resource: @resource, model: @resource.model, user: @resource.user, view: @view)
|
|
30
30
|
.component_for_view(:edit)
|
|
31
|
-
.new(field: field, resource: @resource, index: index, form: form,
|
|
31
|
+
.new(field: field, resource: @resource, index: index, form: form, compact: true)
|
|
32
32
|
%>
|
|
33
33
|
<% end %>
|
|
34
34
|
</div>
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
<%
|
|
3
3
|
classes = 'absolute inset-auto left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2'
|
|
4
4
|
label = t 'avo.failed_to_load'
|
|
5
|
+
src_url = params[:src].present? && !params[:src].starts_with?('http://') ? params.permit(:src).fetch(:src) : nil
|
|
5
6
|
%>
|
|
6
7
|
<div class="relative flex-1 py-4">
|
|
7
8
|
<div class="relative block text-gray-300 h-64 w-full">
|
|
8
9
|
<%= svg 'failed_to_load', class: "#{classes} h-52 text-gray-400" %>
|
|
9
10
|
</div>
|
|
10
11
|
<div class="relative block text-center text-lg text-gray-400 font-semibold pb-6"><%= label %> <span class="border-b-2 border-dashed"><%= params[:turbo_frame].to_s.humanize.downcase if params[:turbo_frame].present? %></span> frame</div>
|
|
11
|
-
<% if Rails.env.development? %>
|
|
12
|
+
<% if Rails.env.development? && src_url %>
|
|
12
13
|
<div class="text-center text-sm w-full pb-3">
|
|
13
|
-
This is not an issue with Avo. Use <%= link_to 'this page',
|
|
14
|
+
This is not an issue with Avo. Use <%= link_to 'this page', src_url, target: :_blank %> to see why this frame failed to load.
|
|
14
15
|
</div>
|
|
15
16
|
<% end %>
|
|
16
17
|
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ignored_warnings": [
|
|
3
|
+
{
|
|
4
|
+
"warning_type": "Cross-Site Scripting",
|
|
5
|
+
"warning_code": 4,
|
|
6
|
+
"fingerprint": "590cf164dd928ef0bd277c5369426130af896d9fdec6389084d9d4a27076ef13",
|
|
7
|
+
"check_name": "LinkToHref",
|
|
8
|
+
"message": "Unsafe parameter value in `link_to` href",
|
|
9
|
+
"file": "app/views/avo/home/failed_to_load.html.erb",
|
|
10
|
+
"line": 15,
|
|
11
|
+
"link": "https://brakemanscanner.org/docs/warning_types/link_to_href",
|
|
12
|
+
"code": "link_to(\"this page\", (params.permit(:src).fetch(:src) or nil), :target => :_blank)",
|
|
13
|
+
"render_path": [
|
|
14
|
+
{
|
|
15
|
+
"type": "controller",
|
|
16
|
+
"class": "Avo::HomeController",
|
|
17
|
+
"method": "failed_to_load",
|
|
18
|
+
"line": 23,
|
|
19
|
+
"file": "app/controllers/avo/home_controller.rb",
|
|
20
|
+
"rendered": {
|
|
21
|
+
"name": "avo/home/failed_to_load",
|
|
22
|
+
"file": "app/views/avo/home/failed_to_load.html.erb"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"location": {
|
|
27
|
+
"type": "template",
|
|
28
|
+
"template": "avo/home/failed_to_load"
|
|
29
|
+
},
|
|
30
|
+
"user_input": "params.permit(:src).fetch(:src)",
|
|
31
|
+
"confidence": "High",
|
|
32
|
+
"cwe_id": [
|
|
33
|
+
79
|
|
34
|
+
],
|
|
35
|
+
"note": ""
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"updated": "2022-10-05 13:24:40 +0300",
|
|
39
|
+
"brakeman_version": "5.3.1"
|
|
40
|
+
}
|
data/db/factories.rb
CHANGED
|
@@ -75,4 +75,24 @@ FactoryBot.define do
|
|
|
75
75
|
link { Faker::Internet.url }
|
|
76
76
|
course { create :course }
|
|
77
77
|
end
|
|
78
|
+
|
|
79
|
+
factory :city do
|
|
80
|
+
name { Faker::Address.city }
|
|
81
|
+
population { rand(10000..999000) }
|
|
82
|
+
is_capital { [true, false].sample }
|
|
83
|
+
features { Faker::Address.community }
|
|
84
|
+
metadata { Faker::Address.community }
|
|
85
|
+
# image_url { "MyString" }
|
|
86
|
+
description { Faker::Address.community }
|
|
87
|
+
status { ["open", "closed"].sample }
|
|
88
|
+
tiny_description { Faker::Address.community }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
factory :product do
|
|
92
|
+
title { "MyString" }
|
|
93
|
+
description { "MyText" }
|
|
94
|
+
price { 1 }
|
|
95
|
+
status { "MyString" }
|
|
96
|
+
category { "MyString" }
|
|
97
|
+
end
|
|
78
98
|
end
|
data/lib/avo/base_resource.rb
CHANGED
|
@@ -101,6 +101,32 @@ module Avo
|
|
|
101
101
|
|
|
102
102
|
ordering.dig(:actions) || {}
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
def get_record_associations(record)
|
|
106
|
+
record._reflections
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def valid_association_name(record, association_name)
|
|
110
|
+
get_record_associations(record).keys.find do |name|
|
|
111
|
+
name == association_name
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def valid_attachment_name(record, association_name)
|
|
116
|
+
get_record_associations(record).keys.each do |name|
|
|
117
|
+
return association_name if name == "#{association_name}_attachment" || name == "#{association_name}_attachments"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def get_available_models
|
|
122
|
+
ApplicationRecord.descendants
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def valid_model_class(model_class)
|
|
126
|
+
get_available_models.find do |m|
|
|
127
|
+
m.to_s == model_class.to_s
|
|
128
|
+
end
|
|
129
|
+
end
|
|
104
130
|
end
|
|
105
131
|
|
|
106
132
|
def initialize
|
|
@@ -36,7 +36,7 @@ module Avo
|
|
|
36
36
|
possible_resource = "#{resource}Resource".gsub "ResourceResource", "Resource"
|
|
37
37
|
|
|
38
38
|
resources.find do |available_resource|
|
|
39
|
-
possible_resource.
|
|
39
|
+
possible_resource.to_s == available_resource.class.to_s
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -43,6 +43,12 @@ module Avo
|
|
|
43
43
|
|
|
44
44
|
items_holder.heading body, **args
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
def sidebar(**args, &block)
|
|
48
|
+
ensure_items_holder_initialized
|
|
49
|
+
|
|
50
|
+
items_holder.sidebar Avo::SidebarBuilder.parse_block(**args, &block)
|
|
51
|
+
end
|
|
46
52
|
# END DSL methods
|
|
47
53
|
|
|
48
54
|
def items
|
|
@@ -76,6 +82,11 @@ module Avo
|
|
|
76
82
|
fields << extract_fields_from_items(tab)
|
|
77
83
|
end
|
|
78
84
|
end
|
|
85
|
+
|
|
86
|
+
# Dive into sidebar to fetch their fields
|
|
87
|
+
if item.is_sidebar?
|
|
88
|
+
fields << extract_fields_from_items(item)
|
|
89
|
+
end
|
|
79
90
|
end
|
|
80
91
|
|
|
81
92
|
if item.is_field?
|
|
@@ -277,6 +288,17 @@ module Avo
|
|
|
277
288
|
end
|
|
278
289
|
end
|
|
279
290
|
|
|
291
|
+
# Make sure all tabs panelfull_items are setted as inside tabs
|
|
292
|
+
panelfull_items.grep(Avo::TabGroup).each do |tab_group|
|
|
293
|
+
tab_group.items.grep(Avo::Tab).each do |tab|
|
|
294
|
+
tab.items.grep(Avo::Panel).each do |panel|
|
|
295
|
+
panel.items.grep(Avo::Fields::BelongsToField).each do |field|
|
|
296
|
+
field.target = :_top
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
280
302
|
# Add all the panelles fields to a new panel
|
|
281
303
|
main_panel_holder = Avo::ItemsHolder.new
|
|
282
304
|
main_panel_holder.items = panelless_items
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
class Avo::Configuration::Branding
|
|
2
|
-
def initialize(colors: nil, chart_colors: nil, logo: nil, logomark: nil)
|
|
2
|
+
def initialize(colors: nil, chart_colors: nil, logo: nil, logomark: nil, placeholder: nil)
|
|
3
3
|
@colors = colors || {}
|
|
4
4
|
@chart_colors = chart_colors
|
|
5
5
|
@logo = logo
|
|
6
6
|
@logomark = logomark
|
|
7
|
+
@placeholder = placeholder
|
|
7
8
|
|
|
8
9
|
@default_colors = {
|
|
9
10
|
background: "#F6F6F7",
|
|
@@ -15,6 +16,7 @@ class Avo::Configuration::Branding
|
|
|
15
16
|
@default_chart_colors = ["#0B8AE2", "#34C683", "#2AB1EE", "#34C6A8"]
|
|
16
17
|
@default_logo = "/avo-assets/logo.png"
|
|
17
18
|
@default_logomark = "/avo-assets/logomark.png"
|
|
19
|
+
@default_placeholder = "placeholder.svg"
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def css_colors
|
|
@@ -39,6 +41,12 @@ class Avo::Configuration::Branding
|
|
|
39
41
|
@logomark || @default_logomark
|
|
40
42
|
end
|
|
41
43
|
|
|
44
|
+
def placeholder
|
|
45
|
+
return @default_placeholder if Avo::App.license.lacks_with_trial(:branding)
|
|
46
|
+
|
|
47
|
+
@placeholder || @default_placeholder
|
|
48
|
+
end
|
|
49
|
+
|
|
42
50
|
def chart_colors
|
|
43
51
|
return @default_chart_colors if Avo::App.license.lacks_with_trial(:branding)
|
|
44
52
|
|
|
@@ -58,6 +58,8 @@ module Avo
|
|
|
58
58
|
# - is_disabled?
|
|
59
59
|
|
|
60
60
|
class BelongsToField < BaseField
|
|
61
|
+
attr_accessor :target
|
|
62
|
+
|
|
61
63
|
attr_reader :polymorphic_as
|
|
62
64
|
attr_reader :relation_method
|
|
63
65
|
attr_reader :types # for Polymorphic associations
|
|
@@ -77,6 +79,7 @@ module Avo
|
|
|
77
79
|
@allow_via_detaching = args[:allow_via_detaching] == true
|
|
78
80
|
@attach_scope = args[:attach_scope]
|
|
79
81
|
@polymorphic_help = args[:polymorphic_help]
|
|
82
|
+
@target = args[:target]
|
|
80
83
|
end
|
|
81
84
|
|
|
82
85
|
def searchable
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
1
3
|
module Avo
|
|
2
4
|
module Fields
|
|
3
5
|
class HeadingField < BaseField
|
|
4
6
|
attr_reader :as_html
|
|
7
|
+
attr_reader :empty
|
|
5
8
|
|
|
6
9
|
def initialize(content, **args, &block)
|
|
10
|
+
# Mark the field as empty if there's no content passed
|
|
11
|
+
@empty = content.blank?
|
|
12
|
+
# Add dummy content
|
|
13
|
+
content ||= SecureRandom.hex
|
|
14
|
+
|
|
7
15
|
args[:updatable] = false
|
|
8
16
|
|
|
9
17
|
super(content, **args, &block)
|
|
@@ -16,6 +24,13 @@ module Avo
|
|
|
16
24
|
def id
|
|
17
25
|
"heading_#{name.to_s.parameterize.underscore}"
|
|
18
26
|
end
|
|
27
|
+
|
|
28
|
+
# Override the value method if the field is empty
|
|
29
|
+
def value
|
|
30
|
+
return nil if empty
|
|
31
|
+
|
|
32
|
+
super
|
|
33
|
+
end
|
|
19
34
|
end
|
|
20
35
|
end
|
|
21
36
|
end
|
data/lib/avo/items_holder.rb
CHANGED
data/lib/avo/menu/builder.rb
CHANGED
data/lib/avo/menu/menu.rb
CHANGED
data/lib/avo/reloader.rb
CHANGED
|
@@ -20,40 +20,41 @@ class Avo::Reloader
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
private
|
|
23
|
-
def updater
|
|
24
|
-
@updater ||= config.file_watcher.new(files, directories) { reload! }
|
|
25
|
-
end
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Rails.root.join("config", "initializers", "avo.rb"),
|
|
31
|
-
]
|
|
24
|
+
def updater
|
|
25
|
+
@updater ||= config.file_watcher.new(files, directories) { reload! }
|
|
26
|
+
end
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
def files
|
|
29
|
+
# we want to watch some files no matter what
|
|
30
|
+
paths = [
|
|
31
|
+
Rails.root.join("config", "initializers", "avo.rb"),
|
|
32
|
+
]
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
# we want to watch some files only in Avo development
|
|
35
|
+
if reload_lib?
|
|
36
|
+
paths += []
|
|
39
37
|
end
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
paths
|
|
40
|
+
end
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
dirs[Avo::Engine.root.join("lib", "avo").to_s] = ["rb"]
|
|
47
|
-
end
|
|
42
|
+
def directories
|
|
43
|
+
dirs = {}
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
# watch the lib directory in Avo development
|
|
46
|
+
if reload_lib?
|
|
47
|
+
dirs[Avo::Engine.root.join("lib", "avo").to_s] = ["rb"]
|
|
50
48
|
end
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
50
|
+
dirs
|
|
51
|
+
end
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
def config
|
|
54
|
+
Rails.application.config
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def reload_lib?
|
|
58
|
+
Avo::IN_DEVELOPMENT || ENV["AVO_RELOAD_LIB_DIR"]
|
|
59
|
+
end
|
|
59
60
|
end
|
|
@@ -40,7 +40,7 @@ module Avo
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def secret_key_base
|
|
43
|
-
ENV[
|
|
43
|
+
ENV["SECRET_KEY_BASE"] || Rails.application.credentials.secret_key_base || Rails.application.secrets.secret_key_base
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
data/lib/avo/sidebar.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class Avo::Sidebar
|
|
2
|
+
include Avo::Concerns::IsResourceItem
|
|
3
|
+
include Avo::Fields::FieldExtensions::VisibleInDifferentViews
|
|
4
|
+
|
|
5
|
+
class_attribute :item_type, default: :sidebar
|
|
6
|
+
delegate :items, :add_item, to: :items_holder
|
|
7
|
+
|
|
8
|
+
attr_reader :name
|
|
9
|
+
attr_reader :view
|
|
10
|
+
attr_accessor :items_holder
|
|
11
|
+
|
|
12
|
+
def initialize(name: nil, view: nil, **args)
|
|
13
|
+
# Initialize the visibility markers
|
|
14
|
+
super
|
|
15
|
+
|
|
16
|
+
@name = name
|
|
17
|
+
@items_holder = Avo::ItemsHolder.new
|
|
18
|
+
@view = view
|
|
19
|
+
|
|
20
|
+
show_on args[:show_on] if args[:show_on].present?
|
|
21
|
+
hide_on args[:hide_on] if args[:hide_on].present?
|
|
22
|
+
only_on args[:only_on] if args[:only_on].present?
|
|
23
|
+
except_on args[:except_on] if args[:except_on].present?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def hydrate(view: nil)
|
|
27
|
+
@view = view
|
|
28
|
+
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def empty?
|
|
33
|
+
visible_items.blank?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def items
|
|
37
|
+
if self.items_holder.present?
|
|
38
|
+
self.items_holder.items
|
|
39
|
+
else
|
|
40
|
+
[]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def visible_items
|
|
45
|
+
items.map do |item|
|
|
46
|
+
# Remove the fields that shouldn't be visible in this view
|
|
47
|
+
# eg: has_many fields on edit
|
|
48
|
+
if not_visible_field(item)
|
|
49
|
+
nil
|
|
50
|
+
else
|
|
51
|
+
item
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
.compact
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def not_visible_field(item)
|
|
58
|
+
item.is_field? && !item.visible_on?(view)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class Avo::SidebarBuilder
|
|
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 :items, to: :items_holder
|
|
12
|
+
delegate :heading, to: :items_holder
|
|
13
|
+
|
|
14
|
+
def initialize(name: nil, **args)
|
|
15
|
+
@sidebar = Avo::Sidebar.new(**args)
|
|
16
|
+
@items_holder = Avo::ItemsHolder.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Fetch the sidebar
|
|
20
|
+
def build
|
|
21
|
+
@sidebar.items_holder = @items_holder
|
|
22
|
+
@sidebar
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/avo/version.rb
CHANGED
|
@@ -35,7 +35,7 @@ Avo.configure do |config|
|
|
|
35
35
|
# config.locale = 'en-US'
|
|
36
36
|
|
|
37
37
|
## == Resource options ==
|
|
38
|
-
# config.
|
|
38
|
+
# config.resource_controls_placement = :right
|
|
39
39
|
# config.model_resource_mapping = {}
|
|
40
40
|
# config.default_view_type = :table
|
|
41
41
|
# config.per_page = 24
|
|
@@ -71,6 +71,7 @@ Avo.configure do |config|
|
|
|
71
71
|
# chart_colors: ["#0B8AE2", "#34C683", "#2AB1EE", "#34C6A8"],
|
|
72
72
|
# logo: "/avo-assets/logo.png",
|
|
73
73
|
# logomark: "/avo-assets/logomark.png"
|
|
74
|
+
# placeholder: "/avo-assets/placeholder.svg"
|
|
74
75
|
# }
|
|
75
76
|
|
|
76
77
|
## == Breadcrumbs ==
|