avo 2.12.1.pre.1 → 2.13.2.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.

Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +2 -1
  4. data/app/assets/stylesheets/avo.css +1 -1
  5. data/app/assets/stylesheets/css/fields/progress.css +3 -3
  6. data/app/assets/stylesheets/css/pagination.css +0 -4
  7. data/app/assets/stylesheets/css/search.css +1 -1
  8. data/app/assets/stylesheets/css/sidebar.css +1 -1
  9. data/app/assets/stylesheets/css/tags.css +7 -0
  10. data/app/assets/svgs/failed_to_load.svg +4 -5
  11. data/app/assets/svgs/grid-empty-state.svg +10 -11
  12. data/app/assets/svgs/table-empty-state.svg +11 -12
  13. data/app/components/avo/actions_component.html.erb +5 -5
  14. data/app/components/avo/actions_component.rb +12 -3
  15. data/app/components/avo/button_component.rb +3 -5
  16. data/app/components/avo/fields/boolean_field/edit_component.html.erb +1 -1
  17. data/app/components/avo/fields/common/gravatar_viewer_component.html.erb +1 -1
  18. data/app/components/avo/fields/date_field/edit_component.html.erb +0 -3
  19. data/app/components/avo/fields/date_time_field/edit_component.html.erb +0 -2
  20. data/app/components/avo/fields/has_one_field/show_component.html.erb +1 -1
  21. data/app/components/avo/fields/progress_bar_field/index_component.html.erb +1 -1
  22. data/app/components/avo/fields/progress_bar_field/show_component.html.erb +1 -1
  23. data/app/components/avo/fields/tags_field/edit_component.html.erb +1 -1
  24. data/app/components/avo/item_switcher_component.html.erb +1 -1
  25. data/app/components/avo/panel_component.html.erb +1 -1
  26. data/app/components/avo/panel_component.rb +3 -4
  27. data/app/components/avo/profile_item_component.html.erb +1 -1
  28. data/app/components/avo/resource_component.rb +6 -4
  29. data/app/components/avo/sidebar_component.html.erb +1 -1
  30. data/app/components/avo/views/resource_edit_component.html.erb +1 -1
  31. data/app/components/avo/views/resource_index_component.html.erb +1 -1
  32. data/app/components/avo/views/resource_index_component.rb +1 -1
  33. data/app/components/avo/views/resource_show_component.html.erb +138 -48
  34. data/app/components/avo/views/resource_show_component.rb +1 -0
  35. data/app/helpers/avo/resources_helper.rb +2 -2
  36. data/app/javascript/avo.js +0 -1
  37. data/app/javascript/js/controllers/fields/trix_field_controller.js +4 -3
  38. data/app/javascript/js/controllers/item_selector_controller.js +1 -1
  39. data/app/views/avo/associations/new.html.erb +2 -2
  40. data/app/views/avo/base/_multiple_select_filter.html.erb +1 -1
  41. data/app/views/avo/base/_text_filter.html.erb +1 -1
  42. data/app/views/avo/dashboards/show.html.erb +1 -1
  43. data/app/views/avo/debug/index.html.erb +1 -1
  44. data/app/views/avo/debug/report.html.erb +1 -0
  45. data/app/views/avo/home/index.html.erb +1 -1
  46. data/app/views/avo/partials/_branding.html.erb +5 -0
  47. data/app/views/avo/partials/_header.html.erb +1 -1
  48. data/app/views/avo/partials/_logo.html.erb +2 -2
  49. data/app/views/avo/private/_links_and_buttons.html.erb +1 -1
  50. data/app/views/avo/private/design.html.erb +5 -5
  51. data/app/views/layouts/avo/application.html.erb +2 -1
  52. data/lib/avo/base_resource.rb +5 -1
  53. data/lib/avo/concerns/has_editable_controls.rb +34 -0
  54. data/lib/avo/configuration/branding.rb +57 -0
  55. data/lib/avo/configuration.rb +5 -0
  56. data/lib/avo/fields/date_field.rb +1 -3
  57. data/lib/avo/fields/field_extensions/has_include_blank.rb +1 -1
  58. data/lib/avo/fields/key_value_field.rb +6 -6
  59. data/lib/avo/licensing/h_q.rb +12 -4
  60. data/lib/avo/licensing/pro_license.rb +2 -0
  61. data/lib/avo/menu/builder.rb +2 -0
  62. data/lib/avo/resources/controls/action.rb +32 -0
  63. data/lib/avo/resources/controls/actions_list.rb +19 -0
  64. data/lib/avo/resources/controls/back_button.rb +13 -0
  65. data/lib/avo/resources/controls/base_control.rb +59 -0
  66. data/lib/avo/resources/controls/delete_button.rb +13 -0
  67. data/lib/avo/resources/controls/detach_button.rb +13 -0
  68. data/lib/avo/resources/controls/edit_button.rb +13 -0
  69. data/lib/avo/resources/controls/execution_context.rb +58 -0
  70. data/lib/avo/resources/controls/items_holder.rb +19 -0
  71. data/lib/avo/resources/controls/link_to.rb +27 -0
  72. data/lib/avo/version.rb +1 -1
  73. data/lib/generators/avo/templates/action.tt +1 -1
  74. data/lib/generators/avo/templates/initializer/avo.tt +14 -0
  75. data/lib/generators/avo/templates/resource_tools/partial.tt +1 -1
  76. data/lib/generators/avo/templates/standalone_action.tt +1 -1
  77. data/public/avo-assets/avo.css +760 -202
  78. data/public/avo-assets/avo.js +2 -2
  79. data/public/avo-assets/avo.js.map +2 -2
  80. metadata +15 -11
  81. data/app/components/avo/button_component.html.erb +0 -1
  82. data/app/helpers/avo/actions_helper.rb +0 -4
  83. data/app/helpers/avo/attachments_helper.rb +0 -4
  84. data/app/views/kaminari/_first_page.html.erb +0 -3
  85. data/app/views/kaminari/_last_page.html.erb +0 -3
  86. data/app/views/kaminari/_next_page.html.erb +0 -9
  87. data/app/views/kaminari/_page.html.erb +0 -12
  88. data/app/views/kaminari/_prev_page.html.erb +0 -9
  89. data/lib/avo/concerns/has_model.rb +0 -11
@@ -5,60 +5,150 @@
5
5
  selected_resources: [@resource.model.id],
6
6
  **@resource.stimulus_data_attributes
7
7
  } do %>
8
- <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
8
+ <%= render Avo::PanelComponent.new(name: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: 0, data: { panel_id: "main" }) do |c| %>
9
9
  <% c.tools do %>
10
- <% if @reflection.present? && @resource.model.present? %>
11
- <% if can_detach? %>
12
- <%= a_button url: detach_path,
13
- icon: 'detach',
14
- method: :delete,
15
- form_class: 'flex flex-col sm:flex-row sm:inline-flex',
16
- style: :text,
17
- data: {
18
- confirm: "Are you sure you want to detach this #{title}."
19
- } do %>
20
- <%= t('avo.detach_item', item: title).capitalize %>
21
- <% end %>
22
- <% end %>
23
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
24
- <% if can_see_the_edit_button? %>
25
- <%= a_link edit_path,
26
- color: :primary,
27
- style: :primary,
28
- icon: 'edit' do %>
29
- <%= t('avo.edit').capitalize %>
10
+ <% if @resource.has_show_controls? %>
11
+ <% @resource.render_show_controls.each do |control| %>
12
+ <% if control.back_button? %>
13
+ <%= a_link back_path,
14
+ style: :text,
15
+ title: control.title,
16
+ data: {
17
+ tippy: control.title ? :tooltip : nil,
18
+ },
19
+ icon: 'arrow-left' do %>
20
+ <%= control.label %>
21
+ <% end %>
22
+ <% elsif control.delete_button? %>
23
+ <% if can_see_the_destroy_button? %>
24
+ <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
25
+ method: :delete,
26
+ local: true,
27
+ style: :text,
28
+ loading: true,
29
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
30
+ color: :red,
31
+ icon: 'trash',
32
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
33
+ title: control.title,
34
+ data: {
35
+ control: :destroy,
36
+ tippy: control.title ? :tooltip : nil,
37
+ 'resource-id': @resource.model.id,
38
+ } do %>
39
+ <% end %>
40
+ <% end %>
41
+ <% elsif control.actions_list? %>
42
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view, exclude: control.exclude, style: control.style, color: control.color %>
43
+ <% elsif control.edit_button? %>
44
+ <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
45
+ <% end %>
46
+ <%= a_link edit_path,
47
+ color: :primary,
48
+ style: :primary,
49
+ title: control.title,
50
+ data: {
51
+ tippy: control.title ? :tooltip : nil,
52
+ },
53
+ icon: 'edit' do %>
54
+ <%= control.label %>
55
+ <% end %>
56
+ <% elsif control.action? %>
57
+ <%= a_link control.path,
58
+ color: control.color,
59
+ style: control.style,
60
+ icon: control.icon,
61
+ title: control.title,
62
+ data: {
63
+ tippy: control.title ? :tooltip : nil,
64
+ 'turbo-frame': 'actions_show',
65
+ 'action': 'click->actions-picker#visitAction',
66
+ } do %>
67
+ <%= control.label %>
68
+ <% end %>
69
+ <% elsif control.link_to? %>
70
+ <%= a_link control.path,
71
+ color: control.color,
72
+ style: control.style,
73
+ icon: control.icon,
74
+ title: control.title,
75
+ target: control.target,
76
+ class: control.class,
77
+ data: {
78
+ **control.data,
79
+ tippy: control.title ? :tooltip : nil,
80
+ } do %>
81
+ <%= control.label %>
82
+ <% end %>
83
+ <% elsif control.detach_button? %>
84
+ <% if @reflection.present? && @resource.model.present? && can_detach? %>
85
+ <%= a_button url: detach_path,
86
+ icon: 'detach',
87
+ method: :delete,
88
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
89
+ style: :text,
90
+ data: {
91
+ confirm: "Are you sure you want to detach this #{title}."
92
+ } do %>
93
+ <%= t('avo.detach_item', item: title).capitalize %>
94
+ <% end %>
95
+ <% end %>
30
96
  <% end %>
31
97
  <% end %>
32
98
  <% else %>
33
- <%= a_link back_path,
34
- style: :text,
35
- icon: 'arrow-left' do %>
36
- <%= t('avo.go_back') %>
37
- <% end %>
38
- <% if can_see_the_destroy_button? %>
39
- <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
40
- method: :delete,
41
- local: true,
99
+ <% if @reflection.present? && @resource.model.present? %>
100
+ <% if can_detach? %>
101
+ <%= a_button url: detach_path,
102
+ icon: 'detach',
103
+ method: :delete,
104
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
105
+ style: :text,
106
+ data: {
107
+ confirm: "Are you sure you want to detach this #{title}."
108
+ } do %>
109
+ <%= t('avo.detach_item', item: title).capitalize %>
110
+ <% end %>
111
+ <% end %>
112
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
113
+ <% if can_see_the_edit_button? %>
114
+ <%= a_link edit_path,
115
+ color: :primary,
116
+ style: :primary,
117
+ icon: 'edit' do %>
118
+ <%= t('avo.edit').capitalize %>
119
+ <% end %>
120
+ <% end %>
121
+ <% else %>
122
+ <%= a_link back_path,
42
123
  style: :text,
43
- loading: true,
44
- confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
45
- color: :red,
46
- icon: 'trash',
47
- form_class: 'flex flex-col sm:flex-row sm:inline-flex',
48
- data: {
49
- control: :destroy,
50
- 'resource-id': @resource.model.id,
51
- } do %>
52
- <%= t('avo.delete').capitalize %>
124
+ icon: 'arrow-left' do %>
125
+ <%= t('avo.go_back') %>
53
126
  <% end %>
54
- <% end %>
55
- <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
56
- <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
57
- <%= a_link edit_path,
58
- color: :primary,
59
- style: :primary,
60
- icon: 'edit' do %>
61
- <%= t('avo.edit').capitalize %>
127
+ <% if can_see_the_destroy_button? %>
128
+ <%= a_button url: helpers.resource_path(model: @resource.model, resource: @resource),
129
+ method: :delete,
130
+ local: true,
131
+ style: :text,
132
+ loading: true,
133
+ confirm: t('avo.are_you_sure', item: @resource.model.model_name.name.downcase),
134
+ color: :red,
135
+ icon: 'trash',
136
+ form_class: 'flex flex-col sm:flex-row sm:inline-flex',
137
+ data: {
138
+ control: :destroy,
139
+ 'resource-id': @resource.model.id,
140
+ } do %>
141
+ <%= t('avo.delete').capitalize %>
142
+ <% end %>
143
+ <% end %>
144
+ <%= render Avo::ActionsComponent.new actions: @actions, resource: @resource, view: @view %>
145
+ <% if @resource.authorization.authorize_action(:edit, raise_exception: false) %>
146
+ <%= a_link edit_path,
147
+ color: :primary,
148
+ style: :primary,
149
+ icon: 'edit' do %>
150
+ <%= t('avo.edit').capitalize %>
151
+ <% end %>
62
152
  <% end %>
63
153
  <% end %>
64
154
  <% end %>
@@ -17,6 +17,7 @@ class Avo::Views::ResourceShowComponent < Avo::ResourceComponent
17
17
  def title
18
18
  if @reflection.present?
19
19
  return field.name if has_one_field?
20
+
20
21
  reflection_resource.name
21
22
  else
22
23
  @resource.default_panel_name
@@ -47,7 +47,7 @@ module Avo
47
47
 
48
48
  def item_selector_input(floating: false, size: :md)
49
49
  "<input type='checkbox'
50
- class='mx-3 rounded #{"absolute inset-auto left-0 mt-2 z-10 hidden group-hover:block checked:block" if floating} #{size.to_sym == :lg ? "w-5 h-5" : "w-4 h-4"}'
50
+ class='mx-3 rounded checked:bg-primary-400 focus:checked:!bg-primary-400 #{"absolute inset-auto left-0 mt-2 z-10 hidden group-hover:block checked:block" if floating} #{size.to_sym == :lg ? "w-5 h-5" : "w-4 h-4"}'
51
51
  data-action='input->item-selector#toggle input->item-select-all#update'
52
52
  data-item-select-all-target='itemCheckbox'
53
53
  name='#{t "avo.select_item"}'
@@ -58,7 +58,7 @@ module Avo
58
58
 
59
59
  def item_select_all_input
60
60
  "<input type='checkbox'
61
- class='mx-3 rounded w-4 h-4'
61
+ class='mx-3 rounded w-4 h-4 checked:bg-primary-400 focus:checked:!bg-primary-400'
62
62
  data-action='input->item-select-all#toggle'
63
63
  data-item-select-all-target='checkbox'
64
64
  name='#{t "avo.select_all"}'
@@ -10,7 +10,6 @@ import tippy from 'tippy.js'
10
10
 
11
11
  import 'chartkick/chart.js/chart.esm'
12
12
 
13
- // Toastr alerts
14
13
  import './js/active-storage'
15
14
  import './js/controllers'
16
15
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-alert */
1
2
  import 'trix'
2
3
  import { Controller } from '@hotwired/stimulus'
3
4
  import { castBoolean } from '../../helpers/cast_boolean'
@@ -48,7 +49,7 @@ export default class extends Controller {
48
49
  // Prevent file uploads for fields that have attachments disabled.
49
50
  if (this.attachmentsDisabled) {
50
51
  event.preventDefault()
51
- window.toastr.warning('This field has attachments disabled.')
52
+ alert('This field has attachments disabled.')
52
53
 
53
54
  return
54
55
  }
@@ -56,7 +57,7 @@ export default class extends Controller {
56
57
  // Prevent file uploads for resources that haven't been saved yet.
57
58
  if (this.resourceId === '') {
58
59
  event.preventDefault()
59
- window.toastr.warning("You can't upload files into the Trix editor until you save the resource.")
60
+ alert("You can't upload files into the Trix editor until you save the resource.")
60
61
 
61
62
  return
62
63
  }
@@ -64,7 +65,7 @@ export default class extends Controller {
64
65
  // Prevent file uploads for fields without an attachment key.
65
66
  if (this.attachmentKey === '') {
66
67
  event.preventDefault()
67
- window.toastr.warning("You haven't set an <a href='https://google.com' class='!text-blue-700 underline'>attachment_key</a> to this Trix field.")
68
+ alert("You haven't set an `attachment_key` to this Trix field.")
68
69
  }
69
70
  }
70
71
  })
@@ -5,7 +5,7 @@ export default class extends Controller {
5
5
 
6
6
  checkbox = {};
7
7
 
8
- enabledClasses = ['text-black', 'hover:bg-blue-500', 'hover:text-white']
8
+ enabledClasses = ['text-black']
9
9
 
10
10
  disabledClasses = ['text-gray-500']
11
11
 
@@ -34,10 +34,10 @@
34
34
  </div>
35
35
 
36
36
  <% c.controls do %>
37
- <%= a_button 'data-action': 'click->modal#close', size: :sm do %>
37
+ <%= a_button 'data-action': 'click->modal#close', size: :sm, style: :outline, color: :primary do %>
38
38
  <%= t('avo.cancel') %>
39
39
  <% end %>
40
- <%= a_button type: :submit, color: :green, size: :sm do %>
40
+ <%= a_button type: :submit, style: :primary, color: :primary, size: :sm do %>
41
41
  <%= t('avo.attach') %>
42
42
  <% end %>
43
43
  <% end %>
@@ -12,7 +12,7 @@
12
12
  'data-multiple-select-filter-target': 'selector'
13
13
  %>
14
14
  <div class="flex justify-end">
15
- <%= a_button class: 'mt-4', color: :blue, size: :xs, data: { action: "multiple-select-filter#changeFilter" } do %>
15
+ <%= a_button class: 'mt-4', color: :primary, size: :xs, data: { action: "multiple-select-filter#changeFilter" } do %>
16
16
  Filter by <%=filter.name %>
17
17
  <% end %>
18
18
  </div>
@@ -13,7 +13,7 @@
13
13
  'data-action': 'keypress->text-filter#tryToSubmit'
14
14
  %>
15
15
  <div class="flex justify-end">
16
- <%= a_button class: 'mt-4', color: :blue, data: { action: "text-filter#changeFilter" }, size: :xs do %>
16
+ <%= a_button class: 'mt-4', color: :primary, data: { action: "text-filter#changeFilter" }, size: :xs do %>
17
17
  <%= filter.button_label || "Filter by #{filter.name}" %>
18
18
  <% end %>
19
19
  </div>
@@ -1,4 +1,4 @@
1
- <%= render Avo::PanelComponent.new(title: @dashboard.name, description: @dashboard.description) do |c| %>
1
+ <%= render Avo::PanelComponent.new(name: @dashboard.name, description: @dashboard.description) do |c| %>
2
2
  <% c.bare_content do %>
3
3
  <% if @dashboard.items.present? %>
4
4
  <div class="min-h-24">
@@ -14,7 +14,7 @@
14
14
  hq_payload = Avo::Licensing::HQ.new(request).payload
15
15
  %>
16
16
  <div class="flex flex-col">
17
- <%= render Avo::PanelComponent.new(title: 'Debug Avo', description: 'Use this page to debug the Avo license.') do |c| %>
17
+ <%= render Avo::PanelComponent.new(name: 'Debug Avo', description: 'Use this page to debug the Avo license.') do |c| %>
18
18
  <% c.tools do %>
19
19
  <% end %>
20
20
  <% c.bare_content do %>
@@ -9,6 +9,7 @@
9
9
  </div>
10
10
  <div class="flex justify-end">
11
11
  <%= a_button icon: 'heroicons/outline/clipboard',
12
+ color: :primary,
12
13
  style: :primary,
13
14
  data: {
14
15
  controller: 'copy-to-clipboard',
@@ -1,5 +1,5 @@
1
1
  <div class="flex flex-col">
2
- <%= render Avo::PanelComponent.new(title: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
2
+ <%= render Avo::PanelComponent.new(name: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
3
3
  <% c.body do %>
4
4
  <div class="flex flex-col justify-between py-6 min-h-24">
5
5
  <div class="px-6 space-y-4">
@@ -0,0 +1,5 @@
1
+ <style>
2
+ :root {
3
+ <%= Avo.configuration.branding.css_colors %>
4
+ }
5
+ </style>
@@ -1 +1 @@
1
- <%= link_to Avo.configuration.app_name, '/', class: 'text-blue-500 font-semibold', target: :_blank %>
1
+ <%= link_to Avo.configuration.app_name, '/', class: 'text-primary-500 font-semibold', target: :_blank %>
@@ -1,4 +1,4 @@
1
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' %>
2
+ <%= image_tag Avo.configuration.branding.logo, class: 'hidden sm:block object-contain', title: 'Avo' %>
3
+ <%= image_tag Avo.configuration.branding.logomark, class: 'sm:hidden object-contain', title: 'Avo' %>
4
4
  <% end %>
@@ -2,7 +2,7 @@
2
2
  entities = [:button, :link]
3
3
  sizes = [:xl, :lg, :md, :sm, :xs].reverse
4
4
  styles = [:primary, :outline, :text]
5
- colors = [:primary, :gray, :red, :orange, :green]
5
+ colors = [:primary, :blue, :gray, :red, :orange, :green]
6
6
  states = [:regular, :hover, :disabled, :active]
7
7
  %>
8
8
  <div class="px-6 space-y-4">
@@ -1,20 +1,20 @@
1
1
  <div class="flex flex-col">
2
- <%= render Avo::PanelComponent.new(title: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
2
+ <%= render Avo::PanelComponent.new(name: 'Welcome to Avo', description: 'This page is visible only in development. It will be hidden in other environments.') do |c| %>
3
3
  <% c.tools do %>
4
- <%= a_link('/admin', icon: 'arrow-left', style: :primary, is_link: true) do %>
4
+ <%= a_link('/admin', icon: 'arrow-left', color: :green, style: :primary, is_link: true) do %>
5
5
  Primary
6
6
  <% end %>
7
7
 
8
8
  <%= a_link('/admin', icon: 'arrow-left', style: :outline, is_link: true) do %>
9
- Secondary
9
+ Outline
10
10
  <% end %>
11
11
 
12
12
  <%= a_link('/admin', icon: 'arrow-left', style: :outline, color: :red, is_link: true) do %>
13
13
  Red
14
14
  <% end %>
15
15
 
16
- <%= a_link('/admin', icon: 'arrow-left', style: :outline, color: :orange, is_link: true) do %>
17
- Red
16
+ <%= a_link('/admin', icon: 'arrow-left', style: :text, color: :orange, is_link: true) do %>
17
+ Text
18
18
  <% end %>
19
19
  <% end %>
20
20
 
@@ -7,6 +7,7 @@
7
7
  <%= csp_meta_tag %>
8
8
  <%= render partial: 'avo/partials/javascript' %>
9
9
  <%= render partial: 'avo/partials/head' %>
10
+ <%= render partial: 'avo/partials/branding' %>
10
11
  <% if Avo::PACKED %>
11
12
  <%= javascript_include_tag "/avo-assets/avo", "data-turbo-track": "reload", defer: true %>
12
13
  <%= stylesheet_link_tag "/avo-assets/avo", "data-turbo-track": "reload", defer: true %>
@@ -18,7 +19,7 @@
18
19
  <% end %>
19
20
  <% end %>
20
21
  </head>
21
- <body class="bg-gray-25 os-mac">
22
+ <body class="bg-application os-mac">
22
23
  <div class="relative flex flex-1 w-full min-h-full" data-controller="sidebar" data-sidebar-open-value="<%= @sidebar_open %>">
23
24
  <div class="flex-1 flex flex-col max-w-full">
24
25
  <%= render partial: "avo/partials/navbar" %>
@@ -3,8 +3,8 @@ module Avo
3
3
  extend ActiveSupport::DescendantsTracker
4
4
 
5
5
  include ActionView::Helpers::UrlHelper
6
- include Avo::Concerns::HasModel
7
6
  include Avo::Concerns::HasFields
7
+ include Avo::Concerns::HasEditableControls
8
8
  include Avo::Concerns::HasStimulusControllers
9
9
  include Avo::Concerns::ModelClassConstantized
10
10
 
@@ -439,5 +439,9 @@ module Avo
439
439
  def ordering_host(**args)
440
440
  Avo::Hosts::Ordering.new resource: self, options: self.class.ordering, **args
441
441
  end
442
+
443
+ def has_model_id?
444
+ model.present? && model.id.present?
445
+ end
442
446
  end
443
447
  end
@@ -0,0 +1,34 @@
1
+ module Avo
2
+ module Concerns
3
+ module HasEditableControls
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :show_controls
8
+ class_attribute :show_controls_holder
9
+ class_attribute :show_controls_holder_called, default: false
10
+ end
11
+
12
+ def has_show_controls?
13
+ return false if ::Avo::App.license.lacks_with_trial(:resource_show_controls)
14
+
15
+ self.class.show_controls.present?
16
+ end
17
+
18
+ def render_show_controls
19
+ return [] if ::Avo::App.license.lacks_with_trial(:resource_show_controls)
20
+
21
+ if show_controls.present?
22
+ Avo::Resources::Controls::ExecutionContext.new(
23
+ block: show_controls,
24
+ resource: self,
25
+ record: model,
26
+ view: view
27
+ ).handle.items
28
+ else
29
+ []
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,57 @@
1
+ class Avo::Configuration::Branding
2
+ def initialize(colors: nil, logo: nil, logomark: nil)
3
+ @colors = colors
4
+ @logo = logo
5
+ @logomark = logomark
6
+
7
+ @default_colors = {
8
+ 100 => "206 231 248",
9
+ 400 => "57 158 229",
10
+ 500 => "8 134 222",
11
+ 600 => "6 107 178"
12
+ }
13
+ @default_logo = "/avo-assets/logo.png"
14
+ @default_logomark = "/avo-assets/logomark.png"
15
+ end
16
+
17
+ def css_colors
18
+ rgb_colors.map do |color, value|
19
+ "--color-primary-#{color}: #{value};"
20
+ end.join("\n")
21
+ end
22
+
23
+ def logo
24
+ return @default_logo if Avo::App.license.lacks_with_trial(:branding)
25
+
26
+ @logo || @default_logo
27
+ end
28
+
29
+ def logomark
30
+ return @default_logomark if Avo::App.license.lacks_with_trial(:branding)
31
+
32
+ @logomark || @default_logomark
33
+ end
34
+
35
+ private
36
+
37
+ def colors
38
+ return @default_colors if Avo::App.license.lacks_with_trial(:branding)
39
+
40
+ @colors || @default_colors
41
+ end
42
+
43
+ def rgb_colors
44
+ colors.map do |key, value|
45
+ rgb_value = is_hex?(value) ? hex_to_rgb(value) : value
46
+ [key, rgb_value]
47
+ end.to_h
48
+ end
49
+
50
+ def is_hex?(value)
51
+ value.include? "#"
52
+ end
53
+
54
+ def hex_to_rgb(value)
55
+ value.to_s.match(/^#(..)(..)(..)$/).captures.map(&:hex).join(" ")
56
+ end
57
+ end
@@ -34,6 +34,7 @@ module Avo
34
34
  attr_accessor :buttons_on_form_footers
35
35
  attr_accessor :main_menu
36
36
  attr_accessor :profile_menu
37
+ attr_writer :branding
37
38
 
38
39
  def initialize
39
40
  @root_path = "/avo"
@@ -121,6 +122,10 @@ module Avo
121
122
  def feature_enabled?(feature)
122
123
  !@disabled_features.map(&:to_sym).include?(feature.to_sym)
123
124
  end
125
+
126
+ def branding
127
+ Avo::Configuration::Branding.new(**@branding || {})
128
+ end
124
129
  end
125
130
 
126
131
  def self.configuration
@@ -5,15 +5,13 @@ module Avo
5
5
  attr_reader :picker_format
6
6
  attr_reader :disable_mobile
7
7
  attr_reader :format
8
- attr_reader :relative
9
8
 
10
9
  def initialize(id, **args, &block)
11
10
  super(id, **args, &block)
12
11
 
13
- add_string_prop args, :first_day_of_week, 0
12
+ add_string_prop args, :first_day_of_week, 1
14
13
  add_string_prop args, :picker_format, "Y-m-d"
15
14
  add_string_prop args, :format, "yyyy-LL-dd"
16
- add_boolean_prop args, :relative
17
15
  add_boolean_prop args, :disable_mobile
18
16
  end
19
17
 
@@ -4,7 +4,7 @@ module Avo
4
4
  module HasIncludeBlank
5
5
  def include_blank
6
6
  if @args[:include_blank] == true
7
- placeholder || ''
7
+ placeholder || ""
8
8
  elsif @args[:include_blank] == false
9
9
  false
10
10
  else
@@ -12,8 +12,8 @@ module Avo
12
12
  hide_on :index
13
13
 
14
14
  @key_label = args[:key_label] if args[:key_label].present?
15
- @value_label = args[:value_label]if args[:value_label].present?
16
- @action_text = args[:action_text] if args[:action_text].present?
15
+ @value_label = args[:value_label] if args[:value_label].present?
16
+ @action_text = args[:action_text] if args[:action_text].present? # This should be add_row_label
17
17
  @delete_text = args[:delete_text] if args[:delete_text].present?
18
18
 
19
19
  @disable_editing_keys = args[:disable_editing_keys].present? ? args[:disable_editing_keys] : false
@@ -31,25 +31,25 @@ module Avo
31
31
  def key_label
32
32
  return @key_label if @key_label.present?
33
33
 
34
- I18n.translate('avo.key_value_field.key')
34
+ I18n.translate("avo.key_value_field.key")
35
35
  end
36
36
 
37
37
  def value_label
38
38
  return @value_label if @value_label.present?
39
39
 
40
- I18n.translate('avo.key_value_field.value')
40
+ I18n.translate("avo.key_value_field.value")
41
41
  end
42
42
 
43
43
  def action_text
44
44
  return @action_text if @action_text.present?
45
45
 
46
- I18n.translate('avo.key_value_field.add_row')
46
+ I18n.translate("avo.key_value_field.add_row")
47
47
  end
48
48
 
49
49
  def delete_text
50
50
  return @delete_text if @delete_text.present?
51
51
 
52
- I18n.translate('avo.key_value_field.delete_row')
52
+ I18n.translate("avo.key_value_field.delete_row")
53
53
  end
54
54
 
55
55
  def to_permitted_param