avo 2.5.2.pre.5 → 2.6.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.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +4 -3
  4. data/app/assets/stylesheets/avo.css +2 -0
  5. data/app/assets/stylesheets/css/tags.css +16 -0
  6. data/app/components/avo/actions_component.html.erb +1 -1
  7. data/app/components/avo/button_component.rb +49 -18
  8. data/app/components/avo/card_component.rb +12 -0
  9. data/app/components/avo/fields/concerns/item_labels.rb +40 -0
  10. data/app/components/avo/fields/tags_field/edit_component.html.erb +27 -0
  11. data/app/components/avo/fields/tags_field/edit_component.rb +4 -0
  12. data/app/components/avo/fields/tags_field/index_component.html.erb +10 -0
  13. data/app/components/avo/fields/tags_field/index_component.rb +9 -0
  14. data/app/components/avo/fields/tags_field/show_component.html.erb +7 -0
  15. data/app/components/avo/fields/tags_field/show_component.rb +7 -0
  16. data/app/components/avo/fields/tags_field/tag_component.html.erb +9 -0
  17. data/app/components/avo/fields/tags_field/tag_component.rb +11 -0
  18. data/app/components/avo/index/resource_table_component.html.erb +1 -1
  19. data/app/components/avo/sidebar/group_component.html.erb +3 -3
  20. data/app/components/avo/sidebar/heading_component.html.erb +2 -2
  21. data/app/components/avo/sidebar/link_component.html.erb +1 -1
  22. data/app/components/avo/sidebar/link_component.rb +1 -1
  23. data/app/components/avo/sidebar_profile_component.html.erb +1 -1
  24. data/app/components/avo/views/resource_index_component.html.erb +2 -2
  25. data/app/components/avo/views/resource_show_component.html.erb +1 -1
  26. data/app/controllers/avo/base_controller.rb +0 -19
  27. data/app/controllers/avo/private_controller.rb +1 -0
  28. data/app/javascript/js/application.js +1 -1
  29. data/app/javascript/js/controllers/base_controller.js +22 -0
  30. data/app/javascript/js/controllers/fields/tags_field_controller.js +86 -0
  31. data/app/javascript/js/controllers/fields/tags_field_helpers.js +47 -0
  32. data/app/javascript/js/controllers/menu_controller.js +2 -2
  33. data/app/javascript/js/controllers.js +2 -0
  34. data/app/views/avo/dashboards/_chartkick_card.html.erb +1 -1
  35. data/app/views/avo/dashboards/_metric_card.html.erb +1 -1
  36. data/app/views/avo/partials/_navbar.html.erb +3 -3
  37. data/app/views/avo/private/_links_and_buttons.html.erb +1 -1
  38. data/app/views/layouts/avo/application.html.erb +1 -1
  39. data/db/factories.rb +2 -0
  40. data/lib/avo/base_resource.rb +6 -0
  41. data/lib/avo/concerns/handles_field_args.rb +36 -0
  42. data/lib/avo/fields/base_field.rb +2 -1
  43. data/lib/avo/fields/tags_field.rb +82 -0
  44. data/lib/avo/hosts/record_host.rb +7 -0
  45. data/lib/avo/licensing/pro_license.rb +2 -1
  46. data/lib/avo/version.rb +1 -1
  47. data/lib/generators/avo/templates/cards/chartkick_card.tt +1 -1
  48. data/lib/generators/avo/templates/cards/chartkick_card_sample.tt +1 -1
  49. data/lib/generators/avo/templates/cards/metric_card.tt +1 -1
  50. data/lib/generators/avo/templates/cards/metric_card_sample.tt +1 -1
  51. data/lib/generators/avo/templates/locales/avo.en.yml +4 -0
  52. data/lib/tasks/avo_tasks.rake +7 -3
  53. data/public/avo-assets/avo.css +722 -71
  54. data/public/avo-assets/avo.js +211 -122
  55. data/public/avo-assets/avo.js.map +3 -3
  56. metadata +20 -7
  57. data/app/assets/builds/avo.css +0 -9032
  58. data/app/assets/builds/avo.js +0 -423
  59. data/app/assets/builds/avo.js.map +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e54bc1e7a03908a2868d5d9033ee9f8bd9b928113cff389fbbb3bea423f43fa
4
- data.tar.gz: 873b114da5fb663ffb558d5583917c10a6e6733a777925b93d0bde96d532ed40
3
+ metadata.gz: 886b0051c7a9b11b46dcd99cdb419559f1b7326d8b8a90a3514d110935bf6d05
4
+ data.tar.gz: 4e21cf6d49133dc5551fdfea9759366bedfd3d487dcfd1df562a40b808383ef2
5
5
  SHA512:
6
- metadata.gz: 5712e7794346582747ad3dfe4e1bf7a380e542f3ed27c643432006f78034a0d71d3d296107dfe44b9675604a10840396df578263dc48fa0a0b0d52f9da9f2168
7
- data.tar.gz: 62c2e65a1d1a762f223aa9f944fe7847f25c6d370000621aa0de807c38c027849248601f0d08b802134728cdba20a9a10e8c875591f3d35efd7978484c72fc14
6
+ metadata.gz: 33608aef95479841514e639bd5e08c81f05a1fa4c73fa3067b59530774e7f11024a5f3e6f9c27e6a10125f9c6d9fef3684436b8b12deeb7c21d988ffa18379ed
7
+ data.tar.gz: ec6b40cda212f0a2ab04d0e672d099a5ebb672b2351cdfa0d8354c7b1ee3334704b5f128421e642d88da09b56fac98178ed7b7da93a370ee8cc53645419559df
data/Gemfile CHANGED
@@ -148,3 +148,5 @@ gem "hightop"
148
148
  gem "active_median"
149
149
 
150
150
  gem 'acts_as_list'
151
+
152
+ gem 'acts-as-taggable-on', '~> 9.0'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (2.5.2.pre.5)
4
+ avo (2.6.0)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -86,6 +86,8 @@ GEM
86
86
  minitest (>= 5.1)
87
87
  tzinfo (~> 2.0)
88
88
  zeitwerk (~> 2.3)
89
+ acts-as-taggable-on (9.0.1)
90
+ activerecord (>= 6.0, < 7.1)
89
91
  acts_as_list (1.0.4)
90
92
  activerecord (>= 4.2)
91
93
  addressable (2.8.0)
@@ -248,8 +250,6 @@ GEM
248
250
  nokogiri (1.13.4)
249
251
  mini_portile2 (~> 2.8.0)
250
252
  racc (~> 1.4)
251
- nokogiri (1.13.4-x86_64-linux)
252
- racc (~> 1.4)
253
253
  orm_adapter (0.5.0)
254
254
  pagy (5.10.1)
255
255
  activesupport
@@ -421,6 +421,7 @@ PLATFORMS
421
421
  DEPENDENCIES
422
422
  active_link_to
423
423
  active_median
424
+ acts-as-taggable-on (~> 9.0)
424
425
  acts_as_list
425
426
  addressable
426
427
  annotate
@@ -4,6 +4,7 @@
4
4
  @import './../../../node_modules/trix/dist/trix.css';
5
5
  @import './../../../node_modules/flatpickr/dist/flatpickr.css';
6
6
  @import './../../../node_modules/@algolia/autocomplete-theme-classic/dist/theme.css';
7
+ @import './../../../node_modules/@yaireo/tagify/dist/tagify.css';
7
8
 
8
9
  @import 'tailwindcss/base';
9
10
 
@@ -17,6 +18,7 @@
17
18
  @import './css/search.css';
18
19
  @import './css/active-storage.css';
19
20
  @import './css/spinner.css';
21
+ @import './css/tags.css';
20
22
 
21
23
  @import './css/components/status.css';
22
24
  @import './css/components/code.css';
@@ -0,0 +1,16 @@
1
+ tags.tagify {
2
+ --tag-inset-shadow-size: 3em;
3
+ }
4
+
5
+ tags.tagify {
6
+ @apply !p-0;
7
+
8
+ span.tagify__input {
9
+ @apply my-1;
10
+ }
11
+ }
12
+
13
+ tag.tagify__tag {
14
+ @apply text-sm my-1 mb-0;
15
+ }
16
+
@@ -35,7 +35,7 @@
35
35
  'actions-picker-target': action.standalone ? 'standaloneAction' : 'resourceAction',
36
36
  'disabled': disabled,
37
37
  },
38
- class: "flex items-center px-4 py-4 w-full font-medium #{disabled ? 'text-gray-500' : 'text-black hover:bg-blue-500 hover:text-white'}" do %>
38
+ class: "flex items-center px-4 py-3 w-full font-semibold text-sm #{disabled ? 'text-gray-500' : 'text-black hover:bg-blue-500 hover:text-white'}" do %>
39
39
  <%= svg 'play', class: 'h-5 mr-1 inline' %> <%= action.action_name %>
40
40
  <% end %>
41
41
  <% end %>
@@ -38,14 +38,15 @@ class Avo::ButtonComponent < ViewComponent::Base
38
38
  end
39
39
 
40
40
  def button_classes
41
- classes = "button-component inline-flex flex-grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 border justify-center active:outline active:outline-1 #{@class}"
41
+ classes = "button-component inline-flex flex-grow-0 items-center font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 transform transition duration-100 cursor-pointer disabled:cursor-not-allowed disabled:opacity-70 border justify-center active:outline active:outline-1 #{@class}"
42
42
 
43
43
  classes += " rounded" if @rounded.present?
44
44
 
45
45
  classes += style_classes
46
46
 
47
- classes += @compact ? " px-1" : " px-4" # Same horizontal padding on all sizes
48
- classes += spacing_classes
47
+ classes += horizontal_padding_classes
48
+ classes += vertical_padding_classes
49
+ classes += text_size_classes
49
50
 
50
51
  classes
51
52
  end
@@ -57,10 +58,14 @@ class Avo::ButtonComponent < ViewComponent::Base
57
58
  def full_content
58
59
  result = ""
59
60
  icon_classes = @icon_class
60
- icon_classes += full_content_icon_classes
61
+ # space out the icon from the text if text is present
62
+ icon_classes += " mr-1" if content.present?
63
+ # add the icon height
64
+ icon_classes += icon_size_classes
61
65
 
66
+ # Add the icon
62
67
  result += helpers.svg(@icon, class: icon_classes) if @icon.present?
63
- result += "<span class='w-0 m-0'>&nbsp;</span>"
68
+
64
69
  if content.present?
65
70
  result += "<span>#{content}</span>"
66
71
  end
@@ -96,21 +101,51 @@ class Avo::ButtonComponent < ViewComponent::Base
96
101
 
97
102
  private
98
103
 
99
- def spacing_classes
104
+ def vertical_padding_classes
100
105
  case @size.to_sym
101
106
  when :xs
102
107
  " py-0"
103
108
  when :sm
104
109
  " py-1"
105
110
  when :md
106
- " py-2"
111
+ " py-1.5"
107
112
  when :lg
113
+ " py-2"
114
+ when :xl
108
115
  " py-3"
109
116
  else
110
117
  ""
111
118
  end
112
119
  end
113
120
 
121
+ def horizontal_padding_classes
122
+ return " px-1" if @compact
123
+
124
+ case @size.to_sym
125
+ when :xs
126
+ " px-2"
127
+ when :sm
128
+ " px-3"
129
+ when :md
130
+ " px-3"
131
+ when :lg
132
+ " px-5"
133
+ when :xl
134
+ " px-6"
135
+ else
136
+ "px-4"
137
+ end
138
+ end
139
+
140
+ def text_size_classes
141
+ case @size.to_sym
142
+ when :xs
143
+ " text-xs"
144
+ else
145
+ " text-sm"
146
+ end
147
+ end
148
+
114
149
  def style_classes
115
150
  case @style
116
151
  when :primary
@@ -118,29 +153,25 @@ class Avo::ButtonComponent < ViewComponent::Base
118
153
  when :outline
119
154
  " bg-white text-#{@color}-500 border-#{@color}-500 hover:bg-#{@color}-100 active:bg-#{@color}-100 active:border-#{@color}-500 active:outline-#{@color}-500"
120
155
  when :text
121
- " text-#{@color}-500 active:outline-#{@color}-500 border-none hover:bg-gray-100"
156
+ " text-#{@color}-500 active:outline-#{@color}-500 hover:bg-gray-100 border-transparent"
122
157
  else
123
158
  ""
124
159
  end
125
160
  end
126
161
 
127
- def full_content_icon_classes
162
+ def icon_size_classes
128
163
  icon_classes = ""
129
164
 
130
165
  case @size
131
166
  when :xs
132
- icon_classes += " h-4"
133
- # When icon is solo we need to add an offset
134
- icon_classes += " my-1" if content.blank?
167
+ icon_classes += " h-4 my-1"
135
168
  when :sm
136
- icon_classes += " h-4"
137
- # When icon is solo we need to add an offset
138
- icon_classes += " my-1" if content.blank?
169
+ icon_classes += " h-4 my-1"
139
170
  when :md
140
- icon_classes += " h-5"
141
- # When icon is solo we need to add an offset
142
- icon_classes += " my-0.5" if content.blank?
171
+ icon_classes += " h-4 my-1"
143
172
  when :lg
173
+ icon_classes += " h-5 my-0.5"
174
+ when :xl
144
175
  icon_classes += " h-6"
145
176
  end
146
177
 
@@ -3,9 +3,21 @@
3
3
  class Avo::CardComponent < ViewComponent::Base
4
4
  def initialize(card: nil)
5
5
  @card = card
6
+
7
+ init_card
6
8
  end
7
9
 
8
10
  def render?
9
11
  !@card.nil?
10
12
  end
13
+
14
+ # Initializing the card byt running the query method.
15
+ # We'll still keep the query block around for compatibility reasons.
16
+ def init_card
17
+ if @card.respond_to? :query
18
+ @card.query
19
+ elsif @card.query_block.present?
20
+ @card.compute_result
21
+ end
22
+ end
11
23
  end
@@ -0,0 +1,40 @@
1
+ module Avo
2
+ module Fields
3
+ module Concerns
4
+ module ItemLabels
5
+ extend ActiveSupport::Concern
6
+
7
+ def value_for_item(item)
8
+ if @field.acts_as_taggable_on.present?
9
+ item["value"]
10
+ else
11
+ item
12
+ end
13
+ end
14
+
15
+ def label_from_item(item)
16
+ value = value_for_item item
17
+
18
+ if suggestions_are_a_hash?
19
+ return suggestions_by_id[value.to_s][:label] if suggestions_by_id[value.to_s].present?
20
+ end
21
+ value
22
+ end
23
+
24
+ def suggestions_by_id
25
+ return {} unless suggestions_are_a_hash?
26
+
27
+ @field.suggestions.map do |suggestion|
28
+ [suggestion[:value].to_s, suggestion]
29
+ end.to_h
30
+ end
31
+
32
+ def suggestions_are_a_hash?
33
+ return false if @field.suggestions.blank?
34
+
35
+ @field.suggestions.first.is_a? Hash
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ <%= edit_field_wrapper field: @field, index: @index, form: @form, resource: @resource, displayed_in_modal: @displayed_in_modal do %>
2
+ <div data-controller="tags-field">
3
+ <%# dummy field %>
4
+ <%= text_field_tag "#{@field.id}-dummy", '',
5
+ class: helpers.input_classes('w-full', has_error: @field.model_errors.include?(@field.id)),
6
+ placeholder: @field.placeholder,
7
+ disabled: @field.readonly,
8
+ value: '',
9
+ data: {
10
+ 'tags-field-target': 'fakeInput',
11
+ } %>
12
+ <%# real field %>
13
+ <%= @form.text_field @field.id,
14
+ class: helpers.input_classes('hidden w-full', has_error: @field.model_errors.include?(@field.id)),
15
+ placeholder: @field.placeholder,
16
+ disabled: @field.readonly,
17
+ value: @field.field_value.to_json,
18
+ data: {
19
+ 'tags-field-target': 'input',
20
+ 'whitelist-items': @field.suggestions.to_json,
21
+ 'disallowed-items': @field.disallowed.to_json,
22
+ 'enforce-suggestions': @field.enforce_suggestions ? 1 : 0,
23
+ 'delimiters': @field.delimiters,
24
+ 'close-on-select': @field.close_on_select ? 1 : 0,
25
+ } %>
26
+ </div>
27
+ <% end %>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::TagsField::EditComponent < Avo::Fields::EditComponent
4
+ end
@@ -0,0 +1,10 @@
1
+ <%= index_field_wrapper field: @field do %>
2
+ <div class="flex gap-1 items-center flex-nowrap">
3
+ <% value.take(3).each do |item| %>
4
+ <%= render Avo::Fields::TagsField::TagComponent.new(label: label_from_item(item)) %>
5
+ <% end %>
6
+ <% if value.count > 3 %>
7
+ <%= render Avo::Fields::TagsField::TagComponent.new(label: '...', title: I18n.t('avo.x_items_more', count: value.count - 3)) %>
8
+ <% end %>
9
+ </div>
10
+ <% end %>
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::TagsField::IndexComponent < Avo::Fields::IndexComponent
4
+ include Avo::Fields::Concerns::ItemLabels
5
+
6
+ def value
7
+ @field.field_value
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ <%= show_field_wrapper field: @field, index: @index do %>
2
+ <div class="flex gap-1 items-center flex-wrap">
3
+ <% @field.field_value.each do |item| %>
4
+ <%= render Avo::Fields::TagsField::TagComponent.new(label: label_from_item(item)) %>
5
+ <% end %>
6
+ </div>
7
+ <% end %>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require_relative 'item_labels'
4
+
5
+ class Avo::Fields::TagsField::ShowComponent < Avo::Fields::ShowComponent
6
+ include Avo::Fields::Concerns::ItemLabels
7
+ end
@@ -0,0 +1,9 @@
1
+ <div class="flex px-2 py-1 rounded bg-gray-100 text-sm text-gray-800 font-normal flex-shrink-0"
2
+ <% if title.present? %>
3
+ data-tippy="tooltip"
4
+ title="<%= title %>"
5
+ <% end %>
6
+ data-target="tag-component"
7
+ >
8
+ <%= label %>
9
+ </div>
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Avo::Fields::TagsField::TagComponent < ViewComponent::Base
4
+ attr_reader :label
5
+ attr_reader :title
6
+
7
+ def initialize(label: nil, title: nil)
8
+ @label = label
9
+ @title = title
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  <div class="w-full ">
2
- <table class="w-full px-4 bg-white rounded" data-resource-name='<%= @resource.model_key %>' data-controller='item-select-all'>
2
+ <table class="w-full px-4 bg-white" data-resource-name='<%= @resource.model_key %>' data-controller='item-select-all'>
3
3
  <%= render partial: 'avo/partials/table_header', locals: {fields: @resource.get_fields(reflection: @reflection)} %>
4
4
  <tbody class="divide-y">
5
5
  <% @resources.each_with_index do |resource, index| %>
@@ -8,18 +8,18 @@
8
8
  >
9
9
  <% if item.name.present? %>
10
10
  <div
11
- class="flex justify-between px-10 pt-2 pb-0 text-gray-400"
11
+ class="flex justify-between px-10 pr-2 pt-2 pb-0 text-gray-400"
12
12
  >
13
13
  <div class="flex items-center text-xs uppercase font-semibold leading-none">
14
14
  <%= item.name %>
15
15
  </div>
16
16
  <% if collapsable %>
17
- <div class="cursor-pointer <%= 'rotate-180' if collapsed %>"
17
+ <div class="cursor-pointer <%= 'rotate-90' if collapsed %>"
18
18
  data-action="click->menu#triggerCollapse"
19
19
  data-menu-target="svg"
20
20
  data-menu-key-param="<%= key %>"
21
21
  >
22
- <%= helpers.svg 'heroicons/outline/chevron-down', class: "h-4"%>
22
+ <%= helpers.svg 'heroicons/outline/chevron-down', class: "h-4 mr-0.5"%>
23
23
  </div>
24
24
  <% end %>
25
25
  </div>
@@ -1,9 +1,9 @@
1
- <div class="flex justify-between px-6 py-2 text-gray-500">
1
+ <div class="flex justify-between px-4 pr-2 py-1 text-gray-500">
2
2
  <div class="flex items-center text-sm uppercase font-semibold leading-none space-x-1">
3
3
  <span class="min-w-[20px]"><%= icon %></span> <span><%= label %></span>
4
4
  </div>
5
5
  <% if collapsable %>
6
- <div class="cursor-pointer <%= 'rotate-180' if collapsed %>"
6
+ <div class="cursor-pointer <%= 'rotate-90' if collapsed %>"
7
7
  data-action="click->menu#triggerCollapse"
8
8
  data-menu-key-param="<%= key %>"
9
9
  data-menu-target="svg"
@@ -2,7 +2,7 @@
2
2
  <%= send link_method, path, class: classes, active: active, target: target do %>
3
3
  <%= label %>
4
4
  <% if target == :_blank %>
5
- <%= helpers.svg('heroicons/outline/external-link', class: 'self-center ml-auto h-3') %>
5
+ <%= helpers.svg('heroicons/outline/external-link', class: 'self-center ml-auto h-3 mr-2') %>
6
6
  <% end %>
7
7
  <% end %>
8
8
  <% else %>
@@ -23,6 +23,6 @@ class Avo::Sidebar::LinkComponent < ViewComponent::Base
23
23
  end
24
24
 
25
25
  def classes
26
- "px-4 flex-1 flex mx-6 leading-none py-2 text-black rounded font-medium hover:bg-gray-100"
26
+ "px-4 pr-0 flex-1 flex mx-6 leading-none py-2 text-black rounded font-medium hover:bg-gray-100"
27
27
  end
28
28
  end
@@ -1,4 +1,4 @@
1
- <div class="text-black Xborder-t border-gray-200 p-4 flex">
1
+ <div class="text-black border-gray-200 p-4 flex">
2
2
  <div class="flex-1 flex space-x-4">
3
3
  <% if avatar.present? %>
4
4
  <div class="relative aspect-square w-10 h-10 overflow-hidden rounded">
@@ -59,14 +59,14 @@
59
59
  <% c.bare_content do %>
60
60
  <% if view_type.to_sym == :table %>
61
61
  <% if @models.present? %>
62
- <div class="mt-8">
62
+ <div class="mt-4">
63
63
  <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
64
64
  </div>
65
65
  <% end %>
66
66
  <% end %>
67
67
  <% if view_type.to_sym == :grid %>
68
68
  <%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
69
- <div class="mt-14">
69
+ <div class="mt-6">
70
70
  <%= render Avo::PaginatorComponent.new pagy: @pagy, turbo_frame: @turbo_frame || 'none', index_params: @index_params, resource: @resource, parent_model: @parent_model %>
71
71
  </div>
72
72
  <% end %>
@@ -1,7 +1,7 @@
1
1
  <div data-model-id="<%= @resource.model.id %>"
2
2
  data-selected-resources-name="<%= @resource.model_key %>"
3
3
  data-selected-resources='["<%= @resource.model.id %>"]'
4
- class="space-y-8"
4
+ class="space-y-12"
5
5
  >
6
6
  <% @resource.panels.each_with_index do |resource_panel, index| %>
7
7
  <%= render Avo::PanelComponent.new(title: title, description: @resource.resource_description, display_breadcrumbs: @reflection.blank?, index: index) do |c| %>
@@ -11,8 +11,6 @@ module Avo
11
11
  before_action :set_edit_title_and_breadcrumbs, only: [:edit, :update]
12
12
  before_action :fill_model, only: [:create, :update]
13
13
  before_action :authorize_action
14
- # before_action :reset_pagination_if_filters_changed, only: :index
15
- # before_action :cache_applied_filters, only: :index
16
14
 
17
15
  def index
18
16
  @page_title = @resource.plural_name.humanize
@@ -360,23 +358,6 @@ module Avo
360
358
  filter_defaults.merge(@applied_filters)
361
359
  end
362
360
 
363
- # Caching these so we know when the filters have changed so we reset the pagination
364
- # def cache_applied_filters
365
- # # puts ["Rails.session->", session].inspect
366
- # session[:avo_applied_filters] = params[:filters]
367
- # # ::Avo::App.cache_store.delete(applied_filters_cache_key) if params[:filters].nil?
368
-
369
- # # ::Avo::App.cache_store.write(applied_filters_cache_key, params[:filters], expires_in: 1.day)
370
- # end
371
-
372
- # def reset_pagination_if_filters_changed
373
- # params[:page] = 1 if params[:filters] != session[:avo_applied_filters]
374
- # end
375
-
376
- # def applied_filters_cache_key
377
- # "avo.base_controller.#{@resource.model_key}.applied_filters"
378
- # end
379
-
380
361
  def set_edit_title_and_breadcrumbs
381
362
  @resource = @resource.hydrate(model: @model, view: :edit, user: _current_user)
382
363
  @page_title = @resource.default_panel_name.to_s
@@ -3,6 +3,7 @@ require_dependency "avo/application_controller"
3
3
  module Avo
4
4
  class PrivateController < ApplicationController
5
5
  def design
6
+ @page_title = "Design [Private]"
6
7
  end
7
8
  end
8
9
  end
@@ -4,7 +4,7 @@ import { Application } from '@hotwired/stimulus'
4
4
  const application = Application.start()
5
5
 
6
6
  // Configure Stimulus development experience
7
- application.debug = false
7
+ application.debug = window?.localStorage.getItem('avo.debug')
8
8
  window.Stimulus = application
9
9
 
10
10
  // Register stimulus-components controller
@@ -0,0 +1,22 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ /**
5
+ * Helper that parses the data attribute value to JSON
6
+ */
7
+ getJsonAttribute(target, attribute, defaultValue = []) {
8
+ let result = defaultValue
9
+ try {
10
+ result = JSON.parse(target.getAttribute(attribute))
11
+ } catch (error) {}
12
+
13
+ return result
14
+ }
15
+
16
+ /**
17
+ * Parses the attribute to boolean
18
+ */
19
+ getBooleanAttribute(target, attribute) {
20
+ return target.getAttribute(attribute) === '1'
21
+ }
22
+ }
@@ -0,0 +1,86 @@
1
+ import { first, isObject, merge } from 'lodash'
2
+ import Tagify from '@yaireo/tagify'
3
+
4
+ import BaseController from '../base_controller'
5
+
6
+ import { suggestionItemTemplate, tagTemplate } from './tags_field_helpers'
7
+
8
+ export default class extends BaseController {
9
+ static targets = ['input', 'fakeInput'];
10
+
11
+ tagify = null;
12
+
13
+ get whitelistItems() {
14
+ return this.getJsonAttribute(this.inputTarget, 'data-whitelist-items', [])
15
+ }
16
+
17
+ get disallowedItems() {
18
+ return this.getJsonAttribute(this.inputTarget, 'data-disallowed-items', [])
19
+ }
20
+
21
+ get enforceSuggestions() {
22
+ return this.getBooleanAttribute(this.inputTarget, 'data-enforce-suggestions')
23
+ }
24
+
25
+ get closeOnSelect() {
26
+ return this.getBooleanAttribute(this.inputTarget, 'data-close-on-select')
27
+ }
28
+
29
+ get delimiters() {
30
+ return this.getJsonAttribute(this.inputTarget, 'data-delimiters', [])
31
+ }
32
+
33
+ get suggestionsAreObjects() {
34
+ return isObject(first(this.whitelistItems))
35
+ }
36
+
37
+ get tagifyOptions() {
38
+ let options = {
39
+ whitelist: this.whitelistItems,
40
+ blacklist: this.disallowedItems,
41
+ enforceWhitelist: this.enforceSuggestions,
42
+ delimiters: this.delimiters.join('|'),
43
+ maxTags: 10,
44
+ dropdown: {
45
+ maxItems: 20,
46
+ enabled: 0,
47
+ closeOnSelect: this.closeOnSelect,
48
+ },
49
+ }
50
+
51
+ if (this.suggestionsAreObjects) {
52
+ options = merge(options, {
53
+ tagTextProp: 'label',
54
+ dropdown: {
55
+ searchKeys: ['label'],
56
+ },
57
+ templates: {
58
+ tag: tagTemplate,
59
+ dropdownItem: suggestionItemTemplate,
60
+ },
61
+ })
62
+ }
63
+
64
+ return options
65
+ }
66
+
67
+ connect() {
68
+ if (this.hasInputTarget) {
69
+ this.hideFakeInput()
70
+ this.showRealInput()
71
+ this.initTagify()
72
+ }
73
+ }
74
+
75
+ initTagify() {
76
+ this.tagify = new Tagify(this.inputTarget, this.tagifyOptions)
77
+ }
78
+
79
+ hideFakeInput() {
80
+ this.fakeInputTarget.classList.add('hidden')
81
+ }
82
+
83
+ showRealInput() {
84
+ this.inputTarget.classList.remove('hidden')
85
+ }
86
+ }