avo 1.21.1.pre.1 → 1.22.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile.lock +57 -57
- data/README.md +1 -1
- data/app/assets/builds/avo.css +405 -224
- data/app/assets/builds/avo.js +16 -6
- data/app/assets/builds/avo.js.map +2 -2
- data/app/assets/stylesheets/avo.css +1 -1
- data/app/assets/stylesheets/css/fonts.css +53 -0
- data/app/assets/stylesheets/css/pagination.css +9 -9
- data/app/assets/stylesheets/css/search.css +3 -2
- data/app/assets/svgs/dashboards-icon.svg +6 -0
- data/app/assets/svgs/resources-icon.svg +13 -0
- data/app/assets/svgs/three-dots.svg +5 -0
- data/app/assets/svgs/tools-icon.svg +3 -0
- data/app/components/avo/button_component.html.erb +1 -0
- data/app/components/avo/button_component.rb +111 -0
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.html.erb +14 -7
- data/app/components/avo/fields/belongs_to_field/autocomplete_component.rb +47 -3
- data/app/components/avo/fields/belongs_to_field/edit_component.html.erb +19 -4
- data/app/components/avo/fields/belongs_to_field/edit_component.rb +37 -0
- data/app/components/avo/fields/boolean_field/index_component.html.erb +1 -1
- data/app/components/avo/index/field_wrapper_component.html.erb +8 -2
- data/app/components/avo/index/field_wrapper_component.rb +2 -1
- data/app/components/avo/index/resource_table_component.html.erb +3 -3
- data/app/components/avo/index/table_row_component.html.erb +1 -1
- data/app/components/avo/navigation_heading_component.html.erb +2 -2
- data/app/components/avo/navigation_heading_component.rb +5 -1
- data/app/components/avo/navigation_link_component.html.erb +2 -2
- data/app/components/avo/navigation_link_component.rb +5 -0
- data/app/components/avo/panel_component.html.erb +5 -3
- data/app/components/avo/sidebar_profile_component.html.erb +28 -0
- data/app/components/avo/sidebar_profile_component.rb +43 -0
- data/app/components/avo/views/resource_index_component.html.erb +8 -7
- data/app/components/avo/views/resource_show_component.html.erb +10 -0
- data/app/controllers/avo/application_controller.rb +1 -1
- data/app/helpers/avo/application_helper.rb +7 -5
- data/app/helpers/avo/resources_helper.rb +2 -2
- data/app/javascript/js/controllers/fields/date_field_controller.js +10 -2
- data/app/javascript/js/controllers/item_selector_controller.js +29 -19
- data/app/javascript/js/controllers/search_controller.js +8 -3
- data/app/views/avo/base/_actions.html.erb +4 -3
- data/app/views/avo/base/_filters.html.erb +3 -1
- data/app/views/avo/partials/_global_search.html.erb +2 -2
- data/app/views/avo/partials/_logo.html.erb +3 -1
- data/app/views/avo/partials/_navbar.html.erb +11 -0
- data/app/views/avo/partials/_paginator.html.erb +4 -3
- data/app/views/avo/partials/_resource_search.html.erb +1 -1
- data/app/views/avo/partials/_sidebar.html.erb +35 -0
- data/app/views/avo/partials/_table_header.html.erb +3 -3
- data/app/views/avo/partials/_turbo_frame_wrap.html.erb +7 -1
- data/app/views/avo/partials/_view_toggle_button.html.erb +22 -16
- data/app/views/layouts/avo/application.html.erb +3 -13
- data/db/factories.rb +7 -3
- data/lib/avo/app.rb +4 -3
- data/lib/avo/base_resource.rb +16 -14
- data/lib/avo/version.rb +1 -1
- data/public/avo-assets/avo.css +405 -224
- data/public/avo-assets/avo.js +16 -6
- data/public/avo-assets/avo.js.map +2 -2
- data/public/avo-assets/fonts/inter-v7-latin-500.eot +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-500.svg +351 -0
- data/public/avo-assets/fonts/inter-v7-latin-500.ttf +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-500.woff +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-500.woff2 +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-600.eot +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-600.svg +351 -0
- data/public/avo-assets/fonts/inter-v7-latin-600.ttf +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-600.woff +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-600.woff2 +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-700.eot +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-700.svg +352 -0
- data/public/avo-assets/fonts/inter-v7-latin-700.ttf +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-700.woff +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-700.woff2 +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-regular.eot +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-regular.svg +351 -0
- data/public/avo-assets/fonts/inter-v7-latin-regular.ttf +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-regular.woff +0 -0
- data/public/avo-assets/fonts/inter-v7-latin-regular.woff2 +0 -0
- data/public/avo-assets/logo.png +0 -0
- metadata +32 -5
- data/app/assets/images/avo/logo.png +0 -0
- data/app/views/avo/partials/_profile_dropdown.html.erb +0 -25
- data/app/views/avo/sidebar/_sidebar.html.erb +0 -33
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Avo::SidebarProfileComponent < ViewComponent::Base
|
4
|
+
attr_reader :user
|
5
|
+
|
6
|
+
def initialize(user:)
|
7
|
+
@user = user
|
8
|
+
end
|
9
|
+
|
10
|
+
def avatar
|
11
|
+
if user.respond_to?(:avatar) && user.avatar.present?
|
12
|
+
user.avatar
|
13
|
+
else
|
14
|
+
""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def name
|
19
|
+
if user.respond_to?(:name) && user.name.present?
|
20
|
+
user.name
|
21
|
+
elsif user.respond_to?(:email) && user.email.present?
|
22
|
+
user.email
|
23
|
+
else
|
24
|
+
"Avo user"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def title
|
29
|
+
if user.respond_to?(:avo_title) && user.avo_title.present?
|
30
|
+
user.avo_title
|
31
|
+
else
|
32
|
+
""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy_user_session_path
|
37
|
+
"destroy_#{Avo.configuration.current_user_resource_name}_session_path".to_sym
|
38
|
+
end
|
39
|
+
|
40
|
+
def can_destroy_user?
|
41
|
+
helpers.main_app.respond_to?(destroy_user_session_path)
|
42
|
+
end
|
43
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<div>
|
2
|
-
<%= render Avo::PanelComponent.new(title: title, description: description, body_classes: 'py-
|
2
|
+
<%= render Avo::PanelComponent.new(title: title, description: description, body_classes: 'py-2', data: { component: 'resources-index' }, display_breadcrumbs: @reflection.blank?) do |c| %>
|
3
3
|
<% c.tools do %>
|
4
4
|
<% if can_see_the_actions_button? %>
|
5
5
|
<%= render 'actions' %>
|
6
6
|
<% end %>
|
7
7
|
|
8
8
|
<% if can_see_the_create_button? %>
|
9
|
-
<%= a_link create_path, 'data-target': 'create' do %>
|
9
|
+
<%= a_link create_path, 'data-target': 'create', color: :primary, variant: :outlined do %>
|
10
10
|
<%= svg 'plus' %> <%= t('avo.create_new_item', item: singular_resource_name.downcase ) %>
|
11
11
|
<% end %>
|
12
12
|
<% end %>
|
@@ -19,7 +19,7 @@
|
|
19
19
|
<% end %>
|
20
20
|
|
21
21
|
<% c.body do %>
|
22
|
-
<div class="flex justify-between
|
22
|
+
<div class="flex justify-between min-h-16"
|
23
23
|
data-selected-resources-name="<%= @resource.model_key %>"
|
24
24
|
data-selected-resources="[]"
|
25
25
|
>
|
@@ -27,11 +27,14 @@
|
|
27
27
|
<%= render partial: 'avo/partials/resource_search', locals: {resource: @resource.model_key} if @resource.search_query.present? %>
|
28
28
|
</div>
|
29
29
|
<div class="flex justify-end items-center px-6 space-x-3">
|
30
|
-
<%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if @models.present? %>
|
31
30
|
<%= render 'filters' if @filters.present? %>
|
31
|
+
|
32
|
+
<%= render partial: 'avo/partials/view_toggle_button', locals: { available_view_types: available_view_types, view_type: view_type, turbo_frame: @turbo_frame } if @models.present? %>
|
32
33
|
</div>
|
33
34
|
</div>
|
35
|
+
<% end %>
|
34
36
|
|
37
|
+
<% c.bare_content do %>
|
35
38
|
<% if view_type.to_sym == :table %>
|
36
39
|
<div class="w-full overflow-auto flex flex-col mt-4">
|
37
40
|
<div class="relative flex-1 flex">
|
@@ -45,13 +48,11 @@
|
|
45
48
|
<% end %>
|
46
49
|
</div>
|
47
50
|
<% end %>
|
48
|
-
<% end %>
|
49
51
|
|
50
|
-
<% c.bare_content do %>
|
51
52
|
<% if view_type.to_sym == :grid %>
|
52
53
|
<%= render Avo::Index::ResourceGridComponent.new(resources: @resources, resource: @resource, reflection: @reflection, parent_model: @parent_model) %>
|
53
54
|
|
54
|
-
<div class="
|
55
|
+
<div class="mt-8 py-6">
|
55
56
|
<%= render partial: 'avo/partials/paginator', locals: { pagy: @pagy, turbo_frame: @turbo_frame || 'none' } %>
|
56
57
|
</div>
|
57
58
|
<% end %>
|
@@ -24,6 +24,16 @@
|
|
24
24
|
<%= svg 'arrow-left' %> <%= t('avo.go_back') %>
|
25
25
|
<% end %>
|
26
26
|
|
27
|
+
<%# -- %>
|
28
|
+
|
29
|
+
<%#= render Avo::ButtonComponent.new(icon: svg('arrow-left'), is_link: true, href: back_path) do %>
|
30
|
+
<%#= t('avo.go_back') %>
|
31
|
+
<%# end %>
|
32
|
+
|
33
|
+
<%#= render Avo::ButtonComponent.new(color: 'green', spinner: true, type: :submit, icon: svg('save')) do %>
|
34
|
+
<%#= t('avo.save').capitalize %>
|
35
|
+
<%# end %>
|
36
|
+
|
27
37
|
<% if can_see_the_destroy_button? %>
|
28
38
|
<%= form_with url: helpers.resource_path(model: @resource.model, resource: @resource), method: :delete, html: { 'data-turbo-frame': params[:turbo_frame] } do |form| %>
|
29
39
|
<%= a_button title: t('avo.delete_item', item: @resource.model.model_name.name.downcase).capitalize,
|
@@ -68,14 +68,14 @@ module Avo
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
def button_classes(extra_classes = nil, color: nil, variant: nil, size: :md)
|
72
|
-
classes = "inline-flex flex-grow-0 items-center text-sm font-
|
71
|
+
def button_classes(extra_classes = nil, color: nil, variant: nil, size: :md, active: false)
|
72
|
+
classes = "inline-flex flex-grow-0 items-center text-sm font-semibold leading-6 fill-current whitespace-nowrap transition duration-100 rounded transform transition duration-100 active:translate-x-px active:translate-y-px cursor-pointer disabled:cursor-not-allowed #{extra_classes}"
|
73
73
|
|
74
74
|
if color.present?
|
75
75
|
if variant.present? && (variant.to_sym == :outlined)
|
76
76
|
classes += " bg-white border"
|
77
77
|
|
78
|
-
classes += " hover:border-#{color}-700 border-#{color}-
|
78
|
+
classes += " hover:border-#{color}-700 border-#{color}-500 text-#{color}-600 hover:text-#{color}-700 disabled:border-gray-300 disabled:text-gray-600"
|
79
79
|
else
|
80
80
|
classes += " text-white bg-#{color}-500 hover:bg-#{color}-600 disabled:bg-#{color}-300"
|
81
81
|
end
|
@@ -88,9 +88,11 @@ module Avo
|
|
88
88
|
when :xs
|
89
89
|
" p-2 py-1"
|
90
90
|
when :sm
|
91
|
-
"
|
91
|
+
" py-1 px-4"
|
92
92
|
when :md
|
93
|
-
"
|
93
|
+
" py-2 px-4"
|
94
|
+
when :xl
|
95
|
+
" py-3 px-4"
|
94
96
|
else
|
95
97
|
" p-4"
|
96
98
|
end
|
@@ -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 #{"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 #{"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 w-4 h-4'
|
61
|
+
class='mx-3 rounded w-4 h-4'
|
62
62
|
data-action='input->item-select-all#toggle'
|
63
63
|
data-item-select-all-target='checkbox'
|
64
64
|
name='#{t "avo.select_all"}'
|
@@ -1,8 +1,14 @@
|
|
1
1
|
import { Controller } from 'stimulus'
|
2
2
|
import { DateTime } from 'luxon'
|
3
|
-
import { castBoolean } from '../../helpers/cast_boolean'
|
4
3
|
import flatpickr from 'flatpickr'
|
5
4
|
|
5
|
+
import { castBoolean } from '../../helpers/cast_boolean'
|
6
|
+
|
7
|
+
// Get the DateTime with the TZ offset applied.
|
8
|
+
function universalTimestamp(timestampStr) {
|
9
|
+
return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000))
|
10
|
+
}
|
11
|
+
|
6
12
|
export default class extends Controller {
|
7
13
|
static targets = ['input']
|
8
14
|
|
@@ -43,7 +49,9 @@ export default class extends Controller {
|
|
43
49
|
// this.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
44
50
|
options.appTimezone = this.inputTarget.dataset.timezone
|
45
51
|
} else {
|
46
|
-
|
52
|
+
// Because the browser treats the date like a timestamp and updates it ot 00:00 hour, when on a western timezone the date will be converted with one day offset.
|
53
|
+
// Ex: 2022-01-30 will render as 2022-01-29 on an American timezone
|
54
|
+
currentValue = universalTimestamp(this.inputTarget.value)
|
47
55
|
}
|
48
56
|
|
49
57
|
options.defaultDate = currentValue
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { Controller } from 'stimulus'
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
-
static targets = ['panel']
|
4
|
+
static targets = ['panel'];
|
5
5
|
|
6
|
-
checkbox = {}
|
6
|
+
checkbox = {};
|
7
7
|
|
8
8
|
get actionsPanelPresent() {
|
9
9
|
return this.actionsButtonElement !== null
|
@@ -17,6 +17,12 @@ export default class extends Controller {
|
|
17
17
|
}
|
18
18
|
}
|
19
19
|
|
20
|
+
get actionLinks() {
|
21
|
+
return document.querySelectorAll(
|
22
|
+
'.js-actions-dropdown a[data-actions-picker-target="resourceAction"]',
|
23
|
+
)
|
24
|
+
}
|
25
|
+
|
20
26
|
set currentIds(value) {
|
21
27
|
this.stateHolderElement.dataset.selectedResources = JSON.stringify(value)
|
22
28
|
|
@@ -32,8 +38,12 @@ export default class extends Controller {
|
|
32
38
|
connect() {
|
33
39
|
this.resourceName = this.element.dataset.resourceName
|
34
40
|
this.resourceId = this.element.dataset.resourceId
|
35
|
-
this.actionsButtonElement = document.querySelector(
|
36
|
-
|
41
|
+
this.actionsButtonElement = document.querySelector(
|
42
|
+
`[data-actions-dropdown-button="${this.resourceName}"]`,
|
43
|
+
)
|
44
|
+
this.stateHolderElement = document.querySelector(
|
45
|
+
`[data-selected-resources-name="${this.resourceName}"]`,
|
46
|
+
)
|
37
47
|
}
|
38
48
|
|
39
49
|
addToSelected() {
|
@@ -45,7 +55,9 @@ export default class extends Controller {
|
|
45
55
|
}
|
46
56
|
|
47
57
|
removeFromSelected() {
|
48
|
-
this.currentIds = this.currentIds.filter(
|
58
|
+
this.currentIds = this.currentIds.filter(
|
59
|
+
(item) => item.toString() !== this.resourceId,
|
60
|
+
)
|
49
61
|
}
|
50
62
|
|
51
63
|
toggle(event) {
|
@@ -59,22 +71,20 @@ export default class extends Controller {
|
|
59
71
|
}
|
60
72
|
|
61
73
|
enableResourceActions() {
|
62
|
-
|
63
|
-
.
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
})
|
74
|
+
this.actionLinks.forEach((link) => {
|
75
|
+
link.classList.add('text-gray-700')
|
76
|
+
link.classList.remove('text-gray-500')
|
77
|
+
link.setAttribute('data-href', link.getAttribute('href'))
|
78
|
+
link.dataset.disabled = false
|
79
|
+
})
|
69
80
|
}
|
70
81
|
|
71
82
|
disableResourceActions() {
|
72
|
-
|
73
|
-
.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
})
|
83
|
+
this.actionLinks.forEach((link) => {
|
84
|
+
link.classList.remove('text-gray-700')
|
85
|
+
link.classList.add('text-gray-500')
|
86
|
+
link.setAttribute('href', link.getAttribute('data-href'))
|
87
|
+
link.dataset.disabled = true
|
88
|
+
})
|
79
89
|
}
|
80
90
|
}
|
@@ -82,7 +82,9 @@ export default class extends Controller {
|
|
82
82
|
|
83
83
|
document.querySelector('.aa-DetachedOverlay').remove()
|
84
84
|
|
85
|
-
this.
|
85
|
+
if (this.hasClearButtonTarget) {
|
86
|
+
this.clearButtonTarget.classList.remove('hidden')
|
87
|
+
}
|
86
88
|
} else {
|
87
89
|
Turbo.visit(item._url, { action: 'advance' })
|
88
90
|
}
|
@@ -157,7 +159,7 @@ export default class extends Controller {
|
|
157
159
|
this.buttonTarget.onclick = () => this.showSearchPanel()
|
158
160
|
|
159
161
|
this.clearValueTargets.forEach((target) => {
|
160
|
-
if (target.getAttribute('value')) {
|
162
|
+
if (target.getAttribute('value') && this.hasClearButtonTarget) {
|
161
163
|
this.clearButtonTarget.classList.remove('hidden')
|
162
164
|
}
|
163
165
|
})
|
@@ -184,6 +186,9 @@ export default class extends Controller {
|
|
184
186
|
},
|
185
187
|
})
|
186
188
|
|
187
|
-
|
189
|
+
// When using search for belongs-to
|
190
|
+
if (this.buttonTarget.dataset.shouldBeDisabled !== 'true') {
|
191
|
+
this.buttonTarget.removeAttribute('disabled')
|
192
|
+
}
|
188
193
|
}
|
189
194
|
}
|
@@ -1,11 +1,12 @@
|
|
1
1
|
<% if @actions.count > 0 %>
|
2
2
|
<div class="relative z-40 js-actions-dropdown" data-controller="toggle-panel actions-picker">
|
3
3
|
<%= a_button class: "focus:outline-none",
|
4
|
-
color: '
|
4
|
+
color: 'primary',
|
5
|
+
size: :xl,
|
5
6
|
'data-action': "click->toggle-panel#togglePanel",
|
6
7
|
'data-actions-dropdown-button': @resource.model_key do
|
7
8
|
%>
|
8
|
-
<%= svg 'arrow-
|
9
|
+
<%= svg 'arrow-circle-right', class: 'h-4 mr-1 transform rotate-90' %> <%= t 'avo.actions' %>
|
9
10
|
<% end %>
|
10
11
|
<div
|
11
12
|
class="absolute block inset-auto right-0 top-full bg-white min-w-300px mt-2 py-4 z-20 shadow-context rounded-xl overflow-hidden hidden"
|
@@ -26,7 +27,7 @@
|
|
26
27
|
'data-turbo-frame': 'actions_show',
|
27
28
|
'data-action': 'click->actions-picker#visitAction',
|
28
29
|
'data-actions-picker-target': action.standalone ? 'standaloneAction' : 'resourceAction',
|
29
|
-
class: "flex items-center w-full py-2 px-4 font-
|
30
|
+
class: "flex items-center w-full py-2 px-4 font-semibold text-gray-700 hover:text-white hover:bg-blue-500 #{disabled ? 'text-gray-500' : 'text-gray-700'}",
|
30
31
|
'data-disabled': disabled do %>
|
31
32
|
<%= svg 'play', class: 'h-5 mr-1 inline' %> <%= action.action_name %>
|
32
33
|
<% end %>
|
@@ -1,7 +1,9 @@
|
|
1
1
|
<div data-controller="toggle-panel">
|
2
2
|
<div class="relative w-full flex justify-between z-30">
|
3
3
|
<%= a_button class: 'focus:outline-none',
|
4
|
-
color: '
|
4
|
+
color: 'secondary',
|
5
|
+
variant: 'outlined',
|
6
|
+
size: :sm,
|
5
7
|
title: t('avo.click_to_reveal_filters'),
|
6
8
|
'data-button': 'resource-filters',
|
7
9
|
'data-action': 'click->toggle-panel#togglePanel',
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<div data-controller="search" class="global-search" data-turbo-remove-before-cache>
|
2
|
-
<div class="inline-block"
|
1
|
+
<div data-controller="search" class="global-search rounded border border-gray-200 pr-4 min-w-[16rem]" data-turbo-remove-before-cache>
|
2
|
+
<div class="inline-block text-gray-500"
|
3
3
|
data-search-target="autocomplete"
|
4
4
|
data-search-resource="global"
|
5
5
|
data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>", "placeholder": "<%= I18n.translate 'avo.search.placeholder' %>", "cancel_button": "<%= I18n.translate 'avo.search.cancel_button' %>"}'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div class="relative bg-white p-2 h-20 w-full flex flex-shrink-0 items-center z-50 px-6 border-b" v-if="layout !== 'blank'">
|
2
|
+
<div>
|
3
|
+
<%= render partial: "avo/partials/header" %>
|
4
|
+
</div>
|
5
|
+
<div class="flex-1 flex ml-4 pl-4">
|
6
|
+
<%= render partial: "avo/partials/global_search" if ::Avo::App.license.has_with_trial(:global_search) && ::Avo.configuration.feature_enabled?(:global_search) %>
|
7
|
+
</div>
|
8
|
+
<div class="align-end">
|
9
|
+
<% # Notifications %>
|
10
|
+
</div>
|
11
|
+
</div>
|
@@ -8,12 +8,10 @@
|
|
8
8
|
per_page_options = per_page_options.sort.uniq
|
9
9
|
%>
|
10
10
|
|
11
|
-
<div class="
|
11
|
+
<div class="flex items-center justify-between aborder-t aborder-slate-200 rounded-xl">
|
12
12
|
<div class="hidden sm:flex-2 sm:flex sm:items-center sm:justify-between">
|
13
13
|
<div>
|
14
14
|
<div class="text-sm leading-5 text-slate-600 flex items-center">
|
15
|
-
<div class="mr-2"><%== pagy_info @pagy %></div>
|
16
|
-
|
17
15
|
<div data-controller="per-page">
|
18
16
|
<div class="flex items-center">
|
19
17
|
<%= select_tag 'per_page',
|
@@ -39,7 +37,10 @@
|
|
39
37
|
</div>
|
40
38
|
</div>
|
41
39
|
<div class="flex">
|
40
|
+
|
42
41
|
<div class="flex-2 sm:flex sm:items-center sm:justify-between">
|
42
|
+
<div class="mr-4"><%== pagy_info @pagy %></div>
|
43
|
+
|
43
44
|
<%# @todo: add first & last page. make the first and last buttons rounded %>
|
44
45
|
<% if @pagy.pages > 1 %>
|
45
46
|
<%== pagy_nav @pagy %>
|
@@ -5,5 +5,5 @@
|
|
5
5
|
data-translation-keys='{"no_item_found": "<%= I18n.translate 'avo.no_item_found' %>"}'
|
6
6
|
>
|
7
7
|
</div>
|
8
|
-
<div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded
|
8
|
+
<div class="hidden relative inline-flex text-gray-400 text-sm border border-gray-300 rounded cursor-pointer" data-search-target="button"></div>
|
9
9
|
</div>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<div class="application-sidebar flex h-full bg-white text-white w-72 z-50 border-r">
|
2
|
+
<div class="flex flex-col w-full">
|
3
|
+
<%= render partial: "avo/partials/logo" %>
|
4
|
+
|
5
|
+
<div class="flex-1 flex flex-col justify-between">
|
6
|
+
<div class="space-y-2">
|
7
|
+
<div class="w-full">
|
8
|
+
<%= render Avo::NavigationLinkComponent.new label: 'Get started', path: avo.root_path, active: :exclusive if Rails.env.development? && Avo.configuration.home_path.nil? %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="w-full">
|
12
|
+
<%= render Avo::NavigationHeadingComponent.new label: t('avo.resources'), icon: svg('resources-icon') %>
|
13
|
+
<% Avo::App.resources_navigation(_current_user).sort_by { |r| r.navigation_label }.each do |resource| %>
|
14
|
+
<%= render Avo::NavigationLinkComponent.new label: resource.navigation_label, path: resources_path(resource: resource) %>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="w-full">
|
19
|
+
<% tools = Avo::App.get_sidebar_partials %>
|
20
|
+
|
21
|
+
<% if tools.present? %>
|
22
|
+
<%= render Avo::NavigationHeadingComponent.new label: t('avo.tools'), icon: svg('tools-icon') %>
|
23
|
+
|
24
|
+
<% tools.each do |partial| %>
|
25
|
+
<%= render partial: "/avo/sidebar/items/#{partial}" %>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<%= render_license_warnings %>
|
32
|
+
<%= render Avo::SidebarProfileComponent.new user: _current_user %>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
<thead class="bg-
|
2
|
+
<thead class="bg-white border-b border-gray-200 pb-1">
|
3
3
|
<th>
|
4
4
|
<%== item_select_all_input %>
|
5
5
|
</th>
|
@@ -28,9 +28,9 @@
|
|
28
28
|
sort_by = field.id
|
29
29
|
sort_direction = 'desc'
|
30
30
|
end
|
31
|
-
classes = "text-
|
31
|
+
classes = "text-gray-500 tracking-tight leading-tight text-sm font-semibold"
|
32
32
|
%>
|
33
|
-
<th class="text-left uppercase px-3 py-
|
33
|
+
<th class="text-left uppercase px-3 py-6 whitespace-nowrap">
|
34
34
|
<% if field.sortable %>
|
35
35
|
<%= link_to params.permit!.merge(sort_by: sort_by, sort_direction: sort_direction), class: "flex items-center #{classes} #{'cursor-pointer' if field.sortable}", 'data-turbo-frame': params[:turbo_frame] do %>
|
36
36
|
<%= field.name %>
|
@@ -1,3 +1,9 @@
|
|
1
1
|
<% if name.present? %><turbo-frame id="<%= name %>"><% end %>
|
2
|
-
|
2
|
+
<%
|
3
|
+
# When rendering the frames the flashed content gets lost.
|
4
|
+
# By including the alerts partial, the stimulus will pick them up and display them to the user.
|
5
|
+
%>
|
6
|
+
<%= render partial: 'avo/partials/alerts'if flash.present? if flash.present? %>
|
7
|
+
|
8
|
+
<%= yield %>
|
3
9
|
<% if name.present? %></turbo-frame><% end %>
|
@@ -1,17 +1,23 @@
|
|
1
|
-
<%
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
<% if available_view_types.count > 1 %>
|
2
|
+
<%
|
3
|
+
info = {
|
4
|
+
table: {
|
5
|
+
new_view_type: 'grid',
|
6
|
+
new_icon: 'view-grid',
|
7
|
+
translation_key: 'avo.grid_view',
|
8
|
+
},
|
9
|
+
grid: {
|
10
|
+
new_view_type: 'table',
|
11
|
+
new_icon: 'view-list',
|
12
|
+
translation_key: 'avo.table_view',
|
13
|
+
},
|
14
|
+
}
|
15
|
+
%>
|
16
|
+
<div class="flex">
|
17
|
+
<% available_view_types.each do |type| %>
|
18
|
+
<%= a_link params.permit!.merge(view_type: type), color: :secondary, variant: :outlined, class: view_type.to_s == type.to_s ? 'bg-gray-200' : '', 'data-turbo-frame': turbo_frame, title: t('avo.switch_to_view', view_type: type), 'data-tippy': 'tooltip' do %>
|
19
|
+
<%= svg info[type][:new_icon] %>
|
20
|
+
<% end %>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
17
23
|
<% end %>
|
@@ -17,24 +17,14 @@
|
|
17
17
|
<%= stylesheet_link_tag "avo", "data-turbo-track": "reload", defer: true %>
|
18
18
|
<% end %>
|
19
19
|
</head>
|
20
|
-
<body class="bg-
|
20
|
+
<body class="bg-gray-100 os-mac">
|
21
21
|
|
22
22
|
<div id="app" class="flex min-h-screen flex-row h-full">
|
23
23
|
<div class="flex flex-1 w-full">
|
24
|
-
<%= render partial: 'avo/
|
24
|
+
<%= render partial: 'avo/partials/sidebar' %>
|
25
25
|
|
26
26
|
<div class="flex-1 flex flex-col h-full overflow-auto">
|
27
|
-
|
28
|
-
<div>
|
29
|
-
<%= render partial: "avo/partials/header" %>
|
30
|
-
</div>
|
31
|
-
<div class="flex-1 flex ml-4 pl-4">
|
32
|
-
<%= render partial: "avo/partials/global_search" if ::Avo::App.license.has_with_trial(:global_search) && ::Avo.configuration.feature_enabled?(:global_search) %>
|
33
|
-
</div>
|
34
|
-
<div class="align-end">
|
35
|
-
<%= render partial: "avo/partials/profile_dropdown" %>
|
36
|
-
</div>
|
37
|
-
</div>
|
27
|
+
<%= render partial: "avo/partials/navbar" %>
|
38
28
|
|
39
29
|
<div class="content p-8 flex-1 flex flex-col justify-between items-stretch <%= @container_classes %>">
|
40
30
|
<%= render partial: "avo/partials/custom_tools_alert" if @custom_tools_alert_visible %>
|
data/db/factories.rb
CHANGED
@@ -58,11 +58,15 @@ FactoryBot.define do
|
|
58
58
|
type { "Spouse" }
|
59
59
|
end
|
60
60
|
|
61
|
+
factory :fish do
|
62
|
+
name { %w[Tilapia Salmon Trout Catfish Pangasius Carp].sample }
|
63
|
+
end
|
64
|
+
|
61
65
|
factory :course do
|
62
|
-
name { Faker::
|
66
|
+
name { Faker::Educator.unique.course_name }
|
63
67
|
end
|
64
68
|
|
65
|
-
factory :
|
66
|
-
|
69
|
+
factory :course_link, class: "Course::Link" do
|
70
|
+
link { Faker::Internet.url }
|
67
71
|
end
|
68
72
|
end
|
data/lib/avo/app.rb
CHANGED
@@ -133,9 +133,10 @@ module Avo
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def resources_navigation(user = nil)
|
136
|
-
get_available_resources(user)
|
137
|
-
resource
|
138
|
-
|
136
|
+
get_available_resources(user)
|
137
|
+
.select do |resource|
|
138
|
+
resource.model_class.present?
|
139
|
+
end
|
139
140
|
.select do |resource|
|
140
141
|
resource.visible_on_sidebar
|
141
142
|
end
|