avo 2.7.0 → 2.9.0
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 +2 -0
- data/Gemfile.lock +6 -4
- data/README.md +11 -0
- data/app/assets/stylesheets/avo.css +4 -4
- data/app/assets/stylesheets/css/{components → fields}/code.css +0 -0
- data/app/assets/stylesheets/css/{components → fields}/progress.css +0 -0
- data/app/assets/stylesheets/css/{components → fields}/status.css +0 -0
- data/app/assets/stylesheets/css/fields/trix.css +17 -0
- data/app/assets/svgs/download-solid-reversed.svg +2 -2
- data/app/components/avo/actions_component.html.erb +5 -13
- data/app/components/avo/actions_component.rb +39 -1
- data/app/components/avo/alert_component.rb +6 -0
- data/app/components/avo/card_component.html.erb +2 -2
- data/app/components/avo/common_field_wrapper_component.html.erb +11 -4
- data/app/components/avo/common_field_wrapper_component.rb +27 -1
- data/app/components/avo/edit/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/fields/badge_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/badge_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +21 -10
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +7 -1
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +27 -15
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +4 -0
- 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/boolean_field/edit_component.html.erb +4 -2
- 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/edit_component.html.erb +7 -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/edit_component.html.erb +7 -5
- data/app/components/avo/fields/code_field/show_component.html.erb +2 -2
- data/app/components/avo/fields/common/key_value_component.html.erb +10 -4
- data/app/components/avo/fields/common/key_value_component.rb +2 -0
- data/app/components/avo/fields/country_field/edit_component.html.erb +4 -2
- data/app/components/avo/fields/country_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/country_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/edit_component.html.erb +6 -4
- data/app/components/avo/fields/date_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/edit_component.html.erb +6 -4
- data/app/components/avo/fields/date_time_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/date_time_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/edit_component.rb +7 -0
- data/app/components/avo/fields/external_image_field/edit_component.html.erb +5 -2
- data/app/components/avo/fields/external_image_field/index_component.html.erb +6 -4
- data/app/components/avo/fields/external_image_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/edit_component.html.erb +6 -1
- data/app/components/avo/fields/file_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/file_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/files_field/edit_component.html.erb +7 -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/gravatar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/has_one_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/hidden_field/edit_component.html.erb +5 -1
- data/app/components/avo/fields/id_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/id_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/index_component.rb +3 -0
- data/app/components/avo/fields/key_value_field/edit_component.html.erb +1 -1
- data/app/components/avo/fields/key_value_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/markdown_field/edit_component.html.erb +8 -5
- data/app/components/avo/fields/markdown_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/edit_component.html.erb +7 -4
- data/app/components/avo/fields/number_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/number_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/password_field/edit_component.html.erb +4 -2
- data/app/components/avo/fields/progress_bar_field/edit_component.html.erb +7 -4
- data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/edit_component.html.erb +9 -3
- data/app/components/avo/fields/select_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/select_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/show_component.rb +3 -0
- data/app/components/avo/fields/status_field/edit_component.html.erb +6 -3
- data/app/components/avo/fields/status_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/status_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/edit_component.html.erb +19 -11
- data/app/components/avo/fields/tags_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/tags_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/edit_component.html.erb +5 -2
- data/app/components/avo/fields/text_field/index_component.html.erb +1 -1
- data/app/components/avo/fields/text_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/textarea_field/edit_component.html.erb +6 -3
- data/app/components/avo/fields/textarea_field/show_component.html.erb +1 -1
- data/app/components/avo/fields/trix_field/edit_component.html.erb +14 -4
- data/app/components/avo/fields/trix_field/edit_component.rb +3 -0
- data/app/components/avo/fields/trix_field/show_component.html.erb +2 -2
- data/app/components/avo/index/field_wrapper_component.html.erb +12 -5
- data/app/components/avo/index/field_wrapper_component.rb +27 -3
- data/app/components/avo/panel_component.rb +4 -3
- data/app/components/avo/resource_component.rb +1 -0
- data/app/components/avo/show/field_wrapper_component.html.erb +1 -1
- data/app/components/avo/show/field_wrapper_component.rb +2 -1
- data/app/components/avo/sidebar/item_switcher_component.html.erb +2 -2
- data/app/components/avo/views/resource_edit_component.html.erb +13 -8
- data/app/components/avo/views/resource_edit_component.rb +32 -3
- data/app/components/avo/views/resource_index_component.html.erb +7 -4
- data/app/components/avo/views/resource_index_component.rb +7 -1
- data/app/components/avo/views/resource_show_component.html.erb +11 -9
- data/app/components/avo/views/resource_show_component.rb +1 -0
- data/app/controllers/avo/actions_controller.rb +4 -1
- data/app/controllers/avo/base_controller.rb +24 -13
- data/app/controllers/avo/cards_controller.rb +25 -0
- data/app/controllers/avo/dashboards_controller.rb +2 -8
- data/app/controllers/avo/home_controller.rb +8 -1
- data/app/controllers/avo/search_controller.rb +7 -1
- data/app/helpers/avo/url_helpers.rb +8 -9
- data/app/javascript/js/controllers/fields/code_field_controller.js +7 -1
- data/app/javascript/js/controllers/fields/key_value_controller.js +1 -0
- data/app/javascript/js/controllers/fields/tags_field_controller.js +0 -1
- data/app/javascript/js/controllers/menu_controller.js +4 -3
- data/app/javascript/js/controllers/resource_edit_controller.js +72 -0
- data/app/javascript/js/controllers/resource_index_controller.js +4 -0
- data/app/javascript/js/controllers/resource_show_controller.js +4 -0
- data/app/javascript/js/controllers/search_controller.js +28 -5
- data/app/javascript/js/controllers.js +8 -0
- data/app/views/avo/associations/new.html.erb +2 -1
- data/app/views/avo/base/_select_filter.html.erb +1 -1
- data/app/views/avo/base/_text_filter.html.erb +1 -0
- data/app/views/avo/base/edit.html.erb +2 -1
- data/app/views/avo/base/new.html.erb +1 -1
- data/app/views/avo/{dashboards → cards}/_chartkick_card.html.erb +0 -0
- data/app/views/avo/{dashboards → cards}/_metric_card.html.erb +0 -0
- data/app/views/avo/{dashboards/card.html.erb → cards/show.html.erb} +0 -0
- data/app/views/avo/partials/_custom_tools_alert.html.erb +21 -7
- data/app/views/avo/partials/_logo.html.erb +3 -2
- data/app/views/avo/partials/_navbar.html.erb +1 -1
- data/app/views/avo/partials/_table_header.html.erb +9 -1
- data/bin/test +1 -0
- data/config/routes.rb +7 -4
- data/db/factories.rb +1 -0
- data/lib/avo/app.rb +18 -1
- data/lib/avo/base_action.rb +16 -4
- data/lib/avo/base_card.rb +0 -23
- data/lib/avo/base_resource.rb +23 -16
- data/lib/avo/concerns/fetches_things.rb +19 -12
- data/lib/avo/concerns/has_fields.rb +93 -0
- data/lib/avo/concerns/has_html_attributes.rb +110 -0
- data/lib/avo/concerns/has_model.rb +11 -0
- data/lib/avo/concerns/has_stimulus_controllers.rb +42 -0
- data/lib/avo/dynamic_router.rb +1 -1
- data/lib/avo/engine.rb +1 -3
- data/lib/avo/fields/base_field.rb +24 -13
- data/lib/avo/fields/concerns/is_required.rb +17 -0
- data/lib/avo/fields/select_field.rb +1 -1
- data/lib/avo/grid_collector.rb +4 -4
- data/lib/avo/hosts/view_record_host.rb +7 -0
- data/lib/avo/html/builder.rb +117 -0
- data/lib/avo/licensing/pro_license.rb +1 -0
- data/lib/avo/menu/base_item.rb +4 -0
- data/lib/avo/menu/dashboard.rb +5 -0
- data/lib/avo/menu/resource.rb +5 -0
- data/lib/avo/version.rb +1 -1
- data/lib/avo.rb +5 -0
- data/lib/generators/avo/install_generator.rb +1 -4
- data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +11 -1
- data/lib/generators/avo/templates/cards/metric_card_sample.tt +11 -1
- data/lib/generators/avo/templates/field/components/edit_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/field/components/index_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/field/components/show_component.html.erb.tt +1 -1
- data/lib/generators/avo/templates/initializer/avo.tt +1 -1
- data/lib/generators/avo/templates/locales/avo.en.yml +3 -3
- data/public/avo-assets/avo.css +473 -1055
- data/public/avo-assets/avo.js +147 -147
- data/public/avo-assets/avo.js.map +3 -3
- data/public/avo-assets/logomark.png +0 -0
- metadata +21 -11
- data/app/components/avo/views/resource_new_component.html.erb +0 -55
- data/app/components/avo/views/resource_new_component.rb +0 -38
- data/lib/avo/fields_collector.rb +0 -70
@@ -22,10 +22,11 @@ export default class extends Controller {
|
|
22
22
|
}
|
23
23
|
|
24
24
|
get initiallyCollapsed() {
|
25
|
-
if (this.
|
26
|
-
|
25
|
+
if (this.defaultState === 'collapsed') {
|
26
|
+
return this.userState === 'collapsed'
|
27
|
+
}
|
27
28
|
|
28
|
-
return
|
29
|
+
return this.userState === 'collapsed'
|
29
30
|
}
|
30
31
|
|
31
32
|
connect() {
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import camelCase from 'lodash/camelCase'
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = []
|
6
|
+
|
7
|
+
static values = {
|
8
|
+
view: String,
|
9
|
+
}
|
10
|
+
|
11
|
+
debugOnInput(e) {
|
12
|
+
// eslint-disable-next-line no-console
|
13
|
+
console.log('onInput', e, e.target.value)
|
14
|
+
}
|
15
|
+
|
16
|
+
toggle({ params }) {
|
17
|
+
const { toggleTarget, toggleTargets } = params
|
18
|
+
|
19
|
+
if (toggleTarget) {
|
20
|
+
this.toggleAvoTarget(toggleTarget)
|
21
|
+
}
|
22
|
+
|
23
|
+
if (toggleTargets && toggleTargets.length > 0) {
|
24
|
+
toggleTargets.forEach(this.toggleAvoTarget.bind(this))
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
disable({ params }) {
|
29
|
+
const { disableTarget, disableTargets } = params
|
30
|
+
|
31
|
+
if (disableTarget) {
|
32
|
+
this.disableAvoTarget(disableTarget)
|
33
|
+
}
|
34
|
+
|
35
|
+
if (disableTargets && disableTargets.length > 0) {
|
36
|
+
disableTargets.forEach(this.disableAvoTarget.bind(this))
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
// Private
|
41
|
+
|
42
|
+
toggleAvoTarget(targetName) {
|
43
|
+
// compose the default wrapper data value
|
44
|
+
const target = camelCase(targetName)
|
45
|
+
const element = document.querySelector(`[data-resource-edit-target="${target}"]`)
|
46
|
+
|
47
|
+
if (element) {
|
48
|
+
element.classList.toggle('hidden')
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
disableAvoTarget(targetName) {
|
53
|
+
// compose the default wrapper data value
|
54
|
+
const target = camelCase(targetName)
|
55
|
+
|
56
|
+
// find & disable direct selector
|
57
|
+
document.querySelectorAll(`[data-resource-edit-target="${target}"]`).forEach(this.toggleItemDisabled)
|
58
|
+
|
59
|
+
// find & disable inputs
|
60
|
+
document.querySelectorAll(`[data-resource-edit-target="${target}"] input`).forEach(this.toggleItemDisabled)
|
61
|
+
|
62
|
+
// find & disable select fields
|
63
|
+
document.querySelectorAll(`[data-resource-edit-target="${target}"] select`).forEach(this.toggleItemDisabled)
|
64
|
+
|
65
|
+
// find & disable buttons for belongs_to
|
66
|
+
document.querySelectorAll(`[data-resource-edit-target="${target}"] [data-slot="value"] button`).forEach(this.toggleItemDisabled)
|
67
|
+
}
|
68
|
+
|
69
|
+
toggleItemDisabled(item) {
|
70
|
+
item.disabled = !item.disabled
|
71
|
+
}
|
72
|
+
}
|
@@ -55,7 +55,10 @@ export default class extends Controller {
|
|
55
55
|
searchUrl(query) {
|
56
56
|
const url = URI()
|
57
57
|
|
58
|
-
|
58
|
+
return url.segment(this.searchSegments()).search(this.searchParams(query)).toString()
|
59
|
+
}
|
60
|
+
|
61
|
+
searchSegments() {
|
59
62
|
let segments = [
|
60
63
|
window.Avo.configuration.root_path,
|
61
64
|
'avo_api',
|
@@ -67,6 +70,19 @@ export default class extends Controller {
|
|
67
70
|
segments = [window.Avo.configuration.root_path, 'avo_api', 'search']
|
68
71
|
}
|
69
72
|
|
73
|
+
return segments
|
74
|
+
}
|
75
|
+
|
76
|
+
searchParams(query) {
|
77
|
+
let params = {
|
78
|
+
q: query,
|
79
|
+
global: false,
|
80
|
+
}
|
81
|
+
|
82
|
+
if (this.isGlobalSearch) {
|
83
|
+
params.global = true
|
84
|
+
}
|
85
|
+
|
70
86
|
if (this.isBelongsToSearch) {
|
71
87
|
params = {
|
72
88
|
...params,
|
@@ -85,13 +101,13 @@ export default class extends Controller {
|
|
85
101
|
}
|
86
102
|
}
|
87
103
|
|
88
|
-
return
|
104
|
+
return params
|
89
105
|
}
|
90
106
|
|
91
107
|
handleOnSelect({ item }) {
|
92
108
|
if (this.isBelongsToSearch) {
|
93
|
-
this.hiddenIdTarget
|
94
|
-
this.buttonTarget
|
109
|
+
this.updateFieldAttribute(this.hiddenIdTarget, 'value', item._id)
|
110
|
+
this.updateFieldAttribute(this.buttonTarget, 'value', item._label)
|
95
111
|
|
96
112
|
document.querySelector('.aa-DetachedOverlay').remove()
|
97
113
|
|
@@ -180,7 +196,7 @@ export default class extends Controller {
|
|
180
196
|
}
|
181
197
|
|
182
198
|
clearValue() {
|
183
|
-
this.clearValueTargets.map((
|
199
|
+
this.clearValueTargets.map((t) => this.updateFieldAttribute(t, 'value', ''))
|
184
200
|
this.clearButtonTarget.classList.add('hidden')
|
185
201
|
}
|
186
202
|
|
@@ -229,4 +245,11 @@ export default class extends Controller {
|
|
229
245
|
this.buttonTarget.removeAttribute('disabled')
|
230
246
|
}
|
231
247
|
}
|
248
|
+
|
249
|
+
// Private
|
250
|
+
|
251
|
+
updateFieldAttribute(target, attribute, value) {
|
252
|
+
target.setAttribute(attribute, value)
|
253
|
+
target.dispatchEvent(new Event('input'))
|
254
|
+
}
|
232
255
|
}
|
@@ -20,6 +20,9 @@ import MobileController from './controllers/mobile_controller'
|
|
20
20
|
import ModalController from './controllers/modal_controller'
|
21
21
|
import MultipleSelectFilterController from './controllers/multiple_select_filter_controller'
|
22
22
|
import PerPageController from './controllers/per_page_controller'
|
23
|
+
import ResourceEditController from './controllers/resource_edit_controller'
|
24
|
+
import ResourceIndexController from './controllers/resource_index_controller'
|
25
|
+
import ResourceShowController from './controllers/resource_show_controller'
|
23
26
|
import SearchController from './controllers/search_controller'
|
24
27
|
import SelectController from './controllers/select_controller'
|
25
28
|
import SelectFilterController from './controllers/select_filter_controller'
|
@@ -46,6 +49,9 @@ application.register('mobile', MobileController)
|
|
46
49
|
application.register('modal', ModalController)
|
47
50
|
application.register('multiple-select-filter', MultipleSelectFilterController)
|
48
51
|
application.register('per-page', PerPageController)
|
52
|
+
application.register('resource-edit', ResourceEditController)
|
53
|
+
application.register('resource-index', ResourceIndexController)
|
54
|
+
application.register('resource-show', ResourceShowController)
|
49
55
|
application.register('search', SearchController)
|
50
56
|
application.register('select', SelectController)
|
51
57
|
application.register('select-filter', SelectFilterController)
|
@@ -61,3 +67,5 @@ application.register('date-field', DateFieldController)
|
|
61
67
|
application.register('key-value', KeyValueController)
|
62
68
|
application.register('simple-mde', SimpleMdeController)
|
63
69
|
application.register('trix-field', TrixFieldController)
|
70
|
+
|
71
|
+
// Custom controllers
|
@@ -16,7 +16,8 @@
|
|
16
16
|
field: @field,
|
17
17
|
model_key: @field.target_resource&.model_key,
|
18
18
|
foreign_key: 'related_id',
|
19
|
-
resource: @resource
|
19
|
+
resource: @resource,
|
20
|
+
view: :new
|
20
21
|
%>
|
21
22
|
<% else %>
|
22
23
|
<div class="flex-1 flex flex-col items-center justify-center px-0 md:px-24 text-base">
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= filter_wrapper name: filter.name do %>
|
7
7
|
<%= select_tag filter.id, options_for_select(filter.options.invert, filter.applied_or_default_value(@applied_filters)),
|
8
8
|
class: input_classes('w-full mb-0'),
|
9
|
-
include_blank: '—',
|
9
|
+
include_blank: filter.class.empty_message || '—',
|
10
10
|
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
11
11
|
'data-filter-class': filter.class,
|
12
12
|
'data-select-filter-target': 'selector',
|
@@ -7,6 +7,7 @@
|
|
7
7
|
<%= text_field_tag filter.id, filter.applied_or_default_value(@applied_filters),
|
8
8
|
class: input_classes('w-full mb-0'),
|
9
9
|
id: "avo_filters_#{filter.id.parameterize.underscore}",
|
10
|
+
placeholder: filter.class.empty_message,
|
10
11
|
'data-filter-class': filter.class.to_s,
|
11
12
|
'data-text-filter-target': 'text',
|
12
13
|
'data-action': 'keypress->text-filter#tryToSubmit'
|
@@ -1 +1,2 @@
|
|
1
|
-
<%= render Avo::Views::ResourceEditComponent.new(resource: @resource) %>
|
1
|
+
<%= render Avo::Views::ResourceEditComponent.new(resource: @resource, view: @view, actions: @actions) %>
|
2
|
+
|
@@ -1 +1 @@
|
|
1
|
-
<%= render Avo::Views::
|
1
|
+
<%= render Avo::Views::ResourceEditComponent.new(resource: @resource, model: @model, view: @view, actions: @actions) %>
|
File without changes
|
File without changes
|
File without changes
|
@@ -5,13 +5,27 @@
|
|
5
5
|
</a>
|
6
6
|
</div>
|
7
7
|
<% end %>
|
8
|
-
|
9
8
|
<% if Avo::App.error_messages.present? %>
|
10
|
-
<% Avo::App.error_messages.each do |
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
<% Avo::App.error_messages.each do |error| %>
|
10
|
+
<% if error.is_a? Hash %>
|
11
|
+
<%
|
12
|
+
url, message, target = error.values_at :url, :message, :target
|
13
|
+
%>
|
14
|
+
<div class="w-full inset-auto bottom-0 z-50 mb-4 opacity-75 hover:opacity-100 transition-opacity duration-150">
|
15
|
+
<a href="<%= url %>" target="<%= target %>" class="rounded bg-orange-700 text-white py-2 px-4 text-sm items-center flex leading-tight space-x-2">
|
16
|
+
<%= svg "exclamation", class: "h-6 inline mr-2 text-bold flex-shrink-0 mr-1" %>
|
17
|
+
<div>
|
18
|
+
<%= simple_format message %>
|
19
|
+
</div>
|
20
|
+
</a>
|
21
|
+
</div>
|
22
|
+
<% elsif error.is_a? String %>
|
23
|
+
<div class="w-full inset-auto bottom-0 z-50 mb-4 opacity-75 hover:opacity-100 transition-opacity duration-150">
|
24
|
+
<div class="rounded bg-orange-700 text-white py-2 px-4 text-sm items-center flex leading-tight space-x-2">
|
25
|
+
<%= svg "exclamation", class: "h-6 inline mr-2 text-bold flex-shrink-0 mr-1" %>
|
26
|
+
<div><%= simple_format error %></div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
16
30
|
<% end %>
|
17
31
|
<% end %>
|
@@ -1,3 +1,4 @@
|
|
1
|
-
<%= link_to root_path, class: 'logo-placeholder h-
|
2
|
-
<%= image_tag '/avo-assets/logo.png', class: '
|
1
|
+
<%= link_to root_path, class: 'logo-placeholder h-full w-full flex justify-start' do %>
|
2
|
+
<%= image_tag '/avo-assets/logo.png', class: 'hidden sm:block object-contain', title: 'Avo' %>
|
3
|
+
<%= image_tag '/avo-assets/logomark.png', class: 'sm:hidden object-contain', title: 'Avo' %>
|
3
4
|
<% end %>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
class="fixed bg-white p-2 w-full flex flex-shrink-0 items-center z-50 px-4 lg:px-4 border-b space-x-4 lg:space-x-0 h-16 <%= 'print:hidden' if Avo.configuration.hide_layout_when_printing %>"
|
3
3
|
v-if="layout !== 'blank'"
|
4
4
|
>
|
5
|
-
<div class="flex items-center space-x-2 lg:space-x-0 w-
|
5
|
+
<div class="flex items-center space-x-2 lg:space-x-0 w-auto lg:w-64 flex-shrink-0 h-full">
|
6
6
|
<%= a_button class: 'lg:hidden', icon: 'menu', size: :xs, compact: true, style: :text, data: { action: 'click->mobile#toggleSidebar' } %>
|
7
7
|
<%= render partial: "avo/partials/logo" %>
|
8
8
|
</div>
|
@@ -30,6 +30,14 @@
|
|
30
30
|
sort_direction = 'desc'
|
31
31
|
end
|
32
32
|
classes = "text-gray-500 tracking-tight leading-tight text-xs font-semibold"
|
33
|
+
classes += case field.index_text_align.to_sym
|
34
|
+
when :right
|
35
|
+
" text-right"
|
36
|
+
when :center
|
37
|
+
" text-center"
|
38
|
+
else
|
39
|
+
""
|
40
|
+
end
|
33
41
|
%>
|
34
42
|
<th class="text-left uppercase px-3 py-2 whitespace-nowrap rounded-l">
|
35
43
|
<% if field.sortable %>
|
@@ -38,7 +46,7 @@
|
|
38
46
|
<%= render partial: 'avo/partials/sortable_component', locals: {field: field} %>
|
39
47
|
<% end %>
|
40
48
|
<% else %>
|
41
|
-
<div class="
|
49
|
+
<div class="block w-full <%= classes %>">
|
42
50
|
<%= field.name %>
|
43
51
|
</div>
|
44
52
|
<% end %>
|
data/bin/test
CHANGED
data/config/routes.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
Avo::Engine.routes.draw do
|
2
2
|
root "home#index"
|
3
3
|
|
4
|
-
get "resources", to: redirect(
|
4
|
+
get "resources", to: redirect(Avo.configuration.root_path)
|
5
|
+
get "dashboards", to: redirect(Avo.configuration.root_path)
|
6
|
+
|
5
7
|
post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
resources :dashboards do
|
10
|
+
resources :cards
|
11
|
+
end
|
9
12
|
|
10
13
|
scope "avo_api", as: "avo_api" do
|
11
14
|
get "/search", to: "search#index"
|
@@ -45,7 +48,7 @@ Avo::Engine.routes.draw do
|
|
45
48
|
post "/debug/refresh_license", to: "debug#refresh_license"
|
46
49
|
end
|
47
50
|
|
48
|
-
if Rails.env.development?
|
51
|
+
if Rails.env.development? || Rails.env.staging?
|
49
52
|
scope "/avo_private", as: "avo_private" do
|
50
53
|
get "/design", to: "private#design"
|
51
54
|
end
|
data/db/factories.rb
CHANGED
data/lib/avo/app.rb
CHANGED
@@ -14,7 +14,7 @@ module Avo
|
|
14
14
|
class_attribute :view_context, default: nil
|
15
15
|
class_attribute :params, default: {}
|
16
16
|
class_attribute :translation_enabled, default: false
|
17
|
-
class_attribute :error_messages
|
17
|
+
class_attribute :error_messages
|
18
18
|
|
19
19
|
class << self
|
20
20
|
def boot
|
@@ -52,6 +52,7 @@ module Avo
|
|
52
52
|
Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.url_options, #{exception.inspect}"
|
53
53
|
end
|
54
54
|
|
55
|
+
check_bad_resources
|
55
56
|
init_resources
|
56
57
|
init_dashboards if license.has_with_trial(:dashboards)
|
57
58
|
end
|
@@ -80,6 +81,22 @@ module Avo
|
|
80
81
|
)
|
81
82
|
end
|
82
83
|
|
84
|
+
def check_bad_resources
|
85
|
+
resources.each do |resource|
|
86
|
+
has_model = resource.model_class.present?
|
87
|
+
|
88
|
+
unless has_model
|
89
|
+
possible_model = resource.class.to_s.gsub 'Resource', ''
|
90
|
+
|
91
|
+
Avo::App.error_messages.push({
|
92
|
+
url: "https://docs.avohq.io/2.0/resources.html#custom-model-class",
|
93
|
+
target: "_blank",
|
94
|
+
message: "#{resource.class.to_s} does not have a valid model assigned. It failed to find the #{possible_model} model. \n\r Please create that model or assign one using self.model_class = YOUR_MODEL"
|
95
|
+
})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
83
100
|
def init_resources
|
84
101
|
self.resources = BaseResource.descendants
|
85
102
|
.select do |resource|
|
data/lib/avo/base_action.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Avo
|
2
2
|
class BaseAction
|
3
|
-
extend FieldsCollector
|
4
3
|
extend HasContext
|
5
4
|
|
5
|
+
include Avo::Concerns::HasFields
|
6
|
+
|
6
7
|
class_attribute :name, default: nil
|
7
8
|
class_attribute :message
|
8
9
|
class_attribute :confirm_button_label
|
@@ -12,7 +13,6 @@ module Avo
|
|
12
13
|
class_attribute :view
|
13
14
|
class_attribute :user
|
14
15
|
class_attribute :resource
|
15
|
-
class_attribute :fields
|
16
16
|
class_attribute :invalid_fields
|
17
17
|
class_attribute :standalone, default: false
|
18
18
|
class_attribute :visible
|
@@ -120,9 +120,14 @@ module Avo
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def visible_in_view
|
123
|
-
|
123
|
+
# Run the visible block if available
|
124
|
+
return instance_exec(resource: self.class.resource, view: view, &visible) if visible.present?
|
125
|
+
|
126
|
+
# Hide on the :new view by default
|
127
|
+
return false if view == :new
|
124
128
|
|
125
|
-
|
129
|
+
# Show on all other views
|
130
|
+
true
|
126
131
|
end
|
127
132
|
|
128
133
|
def param_id
|
@@ -153,6 +158,13 @@ module Avo
|
|
153
158
|
self
|
154
159
|
end
|
155
160
|
|
161
|
+
# Add a placeholder silent message from when a user wants to do a redirect action or something similar
|
162
|
+
def silent
|
163
|
+
add_message nil, :silent
|
164
|
+
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
156
168
|
def redirect_to(path = nil, &block)
|
157
169
|
response[:type] = :redirect
|
158
170
|
response[:path] = if block.present?
|
data/lib/avo/base_card.rb
CHANGED
@@ -52,29 +52,6 @@ module Avo
|
|
52
52
|
@refresh_every || self.class.refresh_every
|
53
53
|
end
|
54
54
|
|
55
|
-
def translated_range(range)
|
56
|
-
return "#{range} days" if range.is_a? Integer
|
57
|
-
|
58
|
-
case range
|
59
|
-
when "MTD"
|
60
|
-
"Month to date"
|
61
|
-
when "QTD"
|
62
|
-
"Quarter to date"
|
63
|
-
when "YTD"
|
64
|
-
"Year to date"
|
65
|
-
when "TODAY"
|
66
|
-
"Today"
|
67
|
-
else
|
68
|
-
range
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def parsed_ranges
|
73
|
-
return unless ranges.present?
|
74
|
-
|
75
|
-
ranges.map { |range| [translated_range(range), range] }
|
76
|
-
end
|
77
|
-
|
78
55
|
def turbo_frame
|
79
56
|
"#{dashboard.id}_#{id}"
|
80
57
|
end
|
data/lib/avo/base_resource.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module Avo
|
2
2
|
class BaseResource
|
3
3
|
extend ActiveSupport::DescendantsTracker
|
4
|
-
extend FieldsCollector
|
5
4
|
extend HasContext
|
6
5
|
|
7
6
|
include ActionView::Helpers::UrlHelper
|
8
7
|
include Avo::Concerns::HasTools
|
8
|
+
include Avo::Concerns::HasModel
|
9
|
+
include Avo::Concerns::HasFields
|
10
|
+
include Avo::Concerns::HasStimulusControllers
|
9
11
|
|
10
|
-
delegate :view_context, to:
|
12
|
+
delegate :view_context, to: ::Avo::App
|
13
|
+
delegate :simple_format, :content_tag, to: :view_context
|
11
14
|
delegate :main_app, to: :view_context
|
12
15
|
delegate :avo, to: :view_context
|
13
16
|
delegate :resource_path, to: :view_context
|
@@ -28,12 +31,10 @@ module Avo
|
|
28
31
|
class_attribute :includes, default: []
|
29
32
|
class_attribute :model_class
|
30
33
|
class_attribute :translation_key
|
31
|
-
class_attribute :translation_enabled, default: false
|
32
34
|
class_attribute :default_view_type, default: :table
|
33
35
|
class_attribute :devise_password_optional, default: false
|
34
36
|
class_attribute :actions_loader
|
35
37
|
class_attribute :filters_loader
|
36
|
-
class_attribute :fields
|
37
38
|
class_attribute :grid_loader
|
38
39
|
class_attribute :visible_on_sidebar, default: true
|
39
40
|
class_attribute :unscoped_queries_on_index, default: false
|
@@ -106,8 +107,6 @@ module Avo
|
|
106
107
|
self.class.model_class = model_class.base_class
|
107
108
|
end
|
108
109
|
end
|
109
|
-
|
110
|
-
self.class.translation_enabled = ::Avo::App.translation_enabled
|
111
110
|
end
|
112
111
|
|
113
112
|
def hydrate(model: nil, view: nil, user: nil, params: nil)
|
@@ -128,7 +127,7 @@ module Avo
|
|
128
127
|
return [] if self.class.fields.blank?
|
129
128
|
|
130
129
|
fields = self.class.fields.map do |field|
|
131
|
-
field.hydrate(resource: self, panel_name: default_panel_name, user: user
|
130
|
+
field.hydrate(resource: self, panel_name: default_panel_name, user: user)
|
132
131
|
end
|
133
132
|
|
134
133
|
if Avo::App.license.lacks_with_trial(:custom_fields)
|
@@ -139,7 +138,7 @@ module Avo
|
|
139
138
|
|
140
139
|
if Avo::App.license.lacks_with_trial(:advanced_fields)
|
141
140
|
fields = fields.reject do |field|
|
142
|
-
field.type ==
|
141
|
+
field.type == "tags"
|
143
142
|
end
|
144
143
|
end
|
145
144
|
|
@@ -288,7 +287,7 @@ module Avo
|
|
288
287
|
end
|
289
288
|
|
290
289
|
def translation_key
|
291
|
-
return "avo.resource_translations.#{class_name_without_resource.underscore}" if
|
290
|
+
return "avo.resource_translations.#{class_name_without_resource.underscore}" if ::Avo::App.translation_enabled
|
292
291
|
|
293
292
|
self.class.translation_key
|
294
293
|
end
|
@@ -298,9 +297,11 @@ module Avo
|
|
298
297
|
|
299
298
|
return @name if @name.present?
|
300
299
|
|
301
|
-
|
302
|
-
|
303
|
-
|
300
|
+
if translation_key && ::Avo::App.translation_enabled
|
301
|
+
t(translation_key, count: 1, default: default).capitalize
|
302
|
+
else
|
303
|
+
default
|
304
|
+
end
|
304
305
|
end
|
305
306
|
|
306
307
|
def singular_name
|
@@ -310,9 +311,11 @@ module Avo
|
|
310
311
|
def plural_name
|
311
312
|
default = name.pluralize
|
312
313
|
|
313
|
-
|
314
|
-
|
315
|
-
|
314
|
+
if translation_key && ::Avo::App.translation_enabled
|
315
|
+
t(translation_key, count: 2, default: default).capitalize
|
316
|
+
else
|
317
|
+
default
|
318
|
+
end
|
316
319
|
end
|
317
320
|
|
318
321
|
def underscore_name
|
@@ -433,7 +436,11 @@ module Avo
|
|
433
436
|
end
|
434
437
|
|
435
438
|
def route_key
|
436
|
-
|
439
|
+
class_name_without_resource.underscore.pluralize
|
440
|
+
end
|
441
|
+
|
442
|
+
def singular_route_key
|
443
|
+
route_key.singularize
|
437
444
|
end
|
438
445
|
|
439
446
|
# This is used as the model class ID
|