flexi_admin 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +42 -0
- data/Rakefile +7 -0
- data/lib/flexi_admin/components/actions/checkbox_component.html.slim +8 -0
- data/lib/flexi_admin/components/actions/checkbox_component.rb +13 -0
- data/lib/flexi_admin/components/actions/select_component.html.slim +11 -0
- data/lib/flexi_admin/components/actions/select_component.rb +17 -0
- data/lib/flexi_admin/components/base_component.rb +19 -0
- data/lib/flexi_admin/components/form/field_component.rb +11 -0
- data/lib/flexi_admin/components/form/label_component.html.slim +2 -0
- data/lib/flexi_admin/components/form/label_component.rb +13 -0
- data/lib/flexi_admin/components/form/rows_component.rb +9 -0
- data/lib/flexi_admin/components/form/text_input_component.html.slim +5 -0
- data/lib/flexi_admin/components/form/text_input_component.rb +17 -0
- data/lib/flexi_admin/components/helpers/action_button_helper.rb +28 -0
- data/lib/flexi_admin/components/helpers/action_helper.rb +12 -0
- data/lib/flexi_admin/components/helpers/icon_helper.rb +11 -0
- data/lib/flexi_admin/components/helpers/link_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/resource_helper.rb +71 -0
- data/lib/flexi_admin/components/helpers/selectable.rb +11 -0
- data/lib/flexi_admin/components/helpers/url_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/value_formatter.rb +32 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.html.slim +2 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.rb +6 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.html.slim +30 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.rb +83 -0
- data/lib/flexi_admin/components/resource/button_select_component.html.slim +13 -0
- data/lib/flexi_admin/components/resource/button_select_component.rb +19 -0
- data/lib/flexi_admin/components/resource/form_component.rb +18 -0
- data/lib/flexi_admin/components/resource/form_element_component.html.slim +3 -0
- data/lib/flexi_admin/components/resource/form_element_component.rb +31 -0
- data/lib/flexi_admin/components/resource/form_mixin.rb +287 -0
- data/lib/flexi_admin/components/resource/link_action_component.html.slim +8 -0
- data/lib/flexi_admin/components/resource/link_action_component.rb +16 -0
- data/lib/flexi_admin/components/resource/show_page_component.rb +21 -0
- data/lib/flexi_admin/components/resource/view_component.html.slim +26 -0
- data/lib/flexi_admin/components/resource/view_component.rb +22 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.html.slim +7 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.rb +29 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.html.slim +32 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.rb +54 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.html.slim +18 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.rb +65 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.html.slim +10 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.rb +16 -0
- data/lib/flexi_admin/components/resources/grid_view_component.rb +89 -0
- data/lib/flexi_admin/components/resources/index_page_component.html.slim +13 -0
- data/lib/flexi_admin/components/resources/index_page_component.rb +19 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.html.slim +2 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.rb +26 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.html.slim +17 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.rb +21 -0
- data/lib/flexi_admin/components/resources/list_view_component.rb +80 -0
- data/lib/flexi_admin/components/resources/pagination_component.html.slim +42 -0
- data/lib/flexi_admin/components/resources/pagination_component.rb +64 -0
- data/lib/flexi_admin/components/resources/resources_component.rb +34 -0
- data/lib/flexi_admin/components/resources/switch_view_component.html.slim +16 -0
- data/lib/flexi_admin/components/resources/switch_view_component.rb +45 -0
- data/lib/flexi_admin/components/resources/view_component.html.slim +12 -0
- data/lib/flexi_admin/components/resources/view_component.rb +15 -0
- data/lib/flexi_admin/components/shared/alert_component.html.slim +2 -0
- data/lib/flexi_admin/components/shared/alert_component.rb +11 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.html.slim +15 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.rb +50 -0
- data/lib/flexi_admin/components/shared/autocomplete.rb +6 -0
- data/lib/flexi_admin/components/shared/datalist_component.html.slim +24 -0
- data/lib/flexi_admin/components/shared/datalist_component.rb +20 -0
- data/lib/flexi_admin/components/shared/link_component.html.slim +3 -0
- data/lib/flexi_admin/components/shared/link_component.rb +15 -0
- data/lib/flexi_admin/components/shared/medium_component.html.slim +7 -0
- data/lib/flexi_admin/components/shared/medium_component.rb +51 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.html.slim +9 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.rb +78 -0
- data/lib/flexi_admin/components/shared/trix_component.html.slim +22 -0
- data/lib/flexi_admin/components/shared/trix_component.rb +21 -0
- data/lib/flexi_admin/components.rb +87 -0
- data/lib/flexi_admin/config.rb +24 -0
- data/lib/flexi_admin/controllers/modals_controller.rb +13 -0
- data/lib/flexi_admin/controllers/resources_controller.rb +240 -0
- data/lib/flexi_admin/controllers.rb +9 -0
- data/lib/flexi_admin/engine.rb +34 -0
- data/lib/flexi_admin/helpers/application_helper.rb +4 -0
- data/lib/flexi_admin/helpers.rb +8 -0
- data/lib/flexi_admin/javascript/controllers/application.js +9 -0
- data/lib/flexi_admin/javascript/controllers/autocomplete_controller.js +142 -0
- data/lib/flexi_admin/javascript/controllers/bulk_action_controller.js +158 -0
- data/lib/flexi_admin/javascript/controllers/button_select_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/datalist_controller.js +104 -0
- data/lib/flexi_admin/javascript/controllers/floating_toc_controller.js +39 -0
- data/lib/flexi_admin/javascript/controllers/form_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/form_validation_controller.js +86 -0
- data/lib/flexi_admin/javascript/controllers/index.js +44 -0
- data/lib/flexi_admin/javascript/controllers/pagination_controller.js +13 -0
- data/lib/flexi_admin/javascript/controllers/sorting_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/switch_view_controller.js +15 -0
- data/lib/flexi_admin/javascript/controllers/toast_controller.js +18 -0
- data/lib/flexi_admin/javascript/controllers/trix_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/uploads_controller.js +164 -0
- data/lib/flexi_admin/javascript/flexi_admin.js +4 -0
- data/lib/flexi_admin/javascript/utils.js +26 -0
- data/lib/flexi_admin/models/concerns/application_resource.rb +25 -0
- data/lib/flexi_admin/models/concerns/parentable.rb +17 -0
- data/lib/flexi_admin/models/context_params.rb +127 -0
- data/lib/flexi_admin/models/resources/context.rb +59 -0
- data/lib/flexi_admin/models/struct.rb +29 -0
- data/lib/flexi_admin/models/toast.rb +23 -0
- data/lib/flexi_admin/models.rb +20 -0
- data/lib/flexi_admin/prompts/codegen-system-prompt.md +50 -0
- data/lib/flexi_admin/railtie.rb +78 -0
- data/lib/flexi_admin/routes.rb +15 -0
- data/lib/flexi_admin/services/code_gen/code_export.rb +22 -0
- data/lib/flexi_admin/services/code_gen/gemini.rb +104 -0
- data/lib/flexi_admin/services/code_gen/gpt.rb +68 -0
- data/lib/flexi_admin/services/code_gen/runner.rb +210 -0
- data/lib/flexi_admin/services/code_gen.rb +14 -0
- data/lib/flexi_admin/services/create_resource.rb +32 -0
- data/lib/flexi_admin/services/update_resource.rb +30 -0
- data/lib/flexi_admin/services.rb +10 -0
- data/lib/flexi_admin/version.rb +10 -0
- data/lib/flexi_admin/views/shared/_redirect.slim +2 -0
- data/lib/flexi_admin/views/shared/_reload.slim +2 -0
- data/lib/flexi_admin/views/shared/_toasts.slim +15 -0
- data/lib/flexi_admin/views/shared/not_authorized.slim +11 -0
- data/lib/flexi_admin.rb +58 -0
- data/lib/tasks/flexi_admin.rake +49 -0
- data/lib/tasks/semantic.rake +57 -0
- metadata +333 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Dependent component, context required.
|
4
|
+
module FlexiAdmin::Components::Resources
|
5
|
+
class GridViewComponent < FlexiAdmin::Components::BaseComponent
|
6
|
+
include FlexiAdmin::Components::Helpers::ValueFormatter
|
7
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
8
|
+
include FlexiAdmin::Components::Helpers::Selectable
|
9
|
+
include FlexiAdmin::Components::Helpers::LinkHelper
|
10
|
+
|
11
|
+
class Element < Struct.new(:attribute, :value, :options, :main_app)
|
12
|
+
include FlexiAdmin::Components::Helpers::UrlHelper
|
13
|
+
|
14
|
+
def formatted_value(value)
|
15
|
+
options[:formatter].call(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def src(image, variant: nil)
|
19
|
+
raise "ActiveStorage::Attached::One required, got #{image.class}" if image.class != ActiveStorage::Attached::One
|
20
|
+
|
21
|
+
return unless variant && image.attached?
|
22
|
+
|
23
|
+
main_app.url_for(image.variant(variant))
|
24
|
+
rescue ActiveStorage::InvariableError
|
25
|
+
main_app.url_for(image)
|
26
|
+
end
|
27
|
+
|
28
|
+
def media_type(resource)
|
29
|
+
resource.media_type.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :context, :resources, :resource
|
34
|
+
attr_accessor :title_element, :header_element, :description_element, :image_element
|
35
|
+
|
36
|
+
def initialize(context)
|
37
|
+
@context = context
|
38
|
+
@resources = context.resources
|
39
|
+
|
40
|
+
@is_selectable = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def grid_view
|
44
|
+
yield
|
45
|
+
|
46
|
+
grid
|
47
|
+
rescue StandardError => e
|
48
|
+
binding.pry if Rails.env.development?
|
49
|
+
end
|
50
|
+
|
51
|
+
def grid
|
52
|
+
render FlexiAdmin::Components::Resources::GridView::GridComponent.new(resources, title_element, header_element,
|
53
|
+
description_element,
|
54
|
+
image_element, context)
|
55
|
+
end
|
56
|
+
|
57
|
+
def render?
|
58
|
+
context.params.current_view == "grid" ||
|
59
|
+
(context.views.first == "grid" && context.params.current_view.blank?)
|
60
|
+
end
|
61
|
+
|
62
|
+
def image(src_attribute, **options, &block)
|
63
|
+
value = block || proc { |resource| resource.send(src_attribute) }
|
64
|
+
|
65
|
+
self.image_element = Element.new(src_attribute, value, options, main_app)
|
66
|
+
end
|
67
|
+
|
68
|
+
def title(attribute, **options, &block)
|
69
|
+
value = block || proc { |resource| resource.send(attribute) }
|
70
|
+
options[:formatter] = format(options[:as] || :text)
|
71
|
+
|
72
|
+
self.title_element = Element.new(attribute, value, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def header(attribute, **options, &block)
|
76
|
+
value = block || proc { |resource| resource.send(attribute) }
|
77
|
+
options[:formatter] = format(options[:as] || :text)
|
78
|
+
|
79
|
+
self.header_element = Element.new(attribute, value, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
def description(attribute, **options, &block)
|
83
|
+
value = block || proc { |resource| resource.send(attribute) }
|
84
|
+
options[:formatter] = format(options[:as] || :text)
|
85
|
+
|
86
|
+
self.description_element = Element.new(attribute, value, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources
|
4
|
+
class IndexPageComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
attr_reader :resources, :context_params, :scope, :title, :show_search, :subtitle
|
6
|
+
|
7
|
+
renders_one :search
|
8
|
+
renders_one :actions
|
9
|
+
|
10
|
+
def initialize(resources, context_params:, scope:, show_search: true, title: nil, subtitle: nil)
|
11
|
+
@resources = resources
|
12
|
+
@context_params = context_params
|
13
|
+
@scope = scope
|
14
|
+
@title = title
|
15
|
+
@show_search = show_search
|
16
|
+
@subtitle = subtitle
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources::ListView
|
4
|
+
class CellComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
attr_reader :value, :width, :justify, :options
|
6
|
+
|
7
|
+
def initialize(value, width: nil, **options)
|
8
|
+
@value = value
|
9
|
+
@width = width
|
10
|
+
@options = options
|
11
|
+
@justify = options[:justify]
|
12
|
+
end
|
13
|
+
|
14
|
+
def width_class
|
15
|
+
width ? "col-#{width}" : "col"
|
16
|
+
end
|
17
|
+
|
18
|
+
def justify_class
|
19
|
+
justify ? "text-#{justify}" : ""
|
20
|
+
end
|
21
|
+
|
22
|
+
def merged_classes
|
23
|
+
[width_class, justify_class].join(" ")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
flexi-table
|
2
|
+
.row.fw-bold.text-muted.py-2
|
3
|
+
- if selectable?
|
4
|
+
.col-auto
|
5
|
+
= render(FlexiAdmin::Components::Actions::CheckboxComponent.new(id: 'all', scope: context.scope, select_all: true))
|
6
|
+
|
7
|
+
- columns.each do |column|
|
8
|
+
= render FlexiAdmin::Components::Shared::Table::HeaderItemComponent.new(column)
|
9
|
+
|
10
|
+
- resources.each do |resource|
|
11
|
+
.row.border-top.py-2
|
12
|
+
- if selectable?
|
13
|
+
.col-auto
|
14
|
+
= render(FlexiAdmin::Components::Actions::CheckboxComponent.new(id: resource.id, scope: context.scope))
|
15
|
+
- columns.each do |column|
|
16
|
+
= render FlexiAdmin::Components::Resources::ListView::CellComponent.new(column.formatted_value(column.value[resource]),
|
17
|
+
**column.options)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources::ListView
|
4
|
+
class TableComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
6
|
+
|
7
|
+
attr_reader :columns, :headers, :resources, :selectable, :context
|
8
|
+
|
9
|
+
def initialize(headers, columns, resources, context, selectable: false)
|
10
|
+
@columns = columns
|
11
|
+
@headers = headers
|
12
|
+
@resources = resources
|
13
|
+
@selectable = selectable
|
14
|
+
@context = context
|
15
|
+
end
|
16
|
+
|
17
|
+
def selectable?
|
18
|
+
@selectable
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Dependent component (context required).
|
4
|
+
module FlexiAdmin::Components::Resources
|
5
|
+
class ListViewComponent < FlexiAdmin::Components::BaseComponent
|
6
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
7
|
+
include FlexiAdmin::Components::Helpers::ValueFormatter
|
8
|
+
include FlexiAdmin::Components::Helpers::Selectable
|
9
|
+
include FlexiAdmin::Components::Helpers::LinkHelper
|
10
|
+
|
11
|
+
class Column < Struct.new(:attribute, :value, :options)
|
12
|
+
def width
|
13
|
+
options[:width]
|
14
|
+
end
|
15
|
+
|
16
|
+
def label
|
17
|
+
options[:label]
|
18
|
+
end
|
19
|
+
|
20
|
+
def sortable?
|
21
|
+
options.key?(:sortable).present? || false
|
22
|
+
end
|
23
|
+
|
24
|
+
def sort_by
|
25
|
+
options[:sortable].is_a?(TrueClass) ? attribute : options[:sortable]
|
26
|
+
end
|
27
|
+
|
28
|
+
def formatted_value(value)
|
29
|
+
options[:formatter].call(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :context, :columns, :resources, :resource
|
34
|
+
|
35
|
+
def initialize(context)
|
36
|
+
@context = context
|
37
|
+
@resources = context.resources
|
38
|
+
@columns = []
|
39
|
+
@headers = []
|
40
|
+
@is_selectable = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def render?
|
44
|
+
context.params.current_view == 'list' ||
|
45
|
+
(context.views.first == 'list' && context.params.current_view.blank?)
|
46
|
+
end
|
47
|
+
|
48
|
+
def as_text(value)
|
49
|
+
value.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def as_date(value, format: nil)
|
53
|
+
return if value.blank?
|
54
|
+
|
55
|
+
I18n.l(value, format:)
|
56
|
+
end
|
57
|
+
|
58
|
+
def list_view
|
59
|
+
yield
|
60
|
+
|
61
|
+
table
|
62
|
+
end
|
63
|
+
|
64
|
+
def table
|
65
|
+
render FlexiAdmin::Components::Resources::ListView::TableComponent.new(headers, columns, resources, context, selectable: true)
|
66
|
+
end
|
67
|
+
|
68
|
+
def column(attribute, options = {}, &block)
|
69
|
+
@columns << build_column(attribute, options, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_column(attribute, options, &block)
|
73
|
+
options[:formatter] = format(options[:as] || :text)
|
74
|
+
|
75
|
+
Column.new(attribute,
|
76
|
+
block || proc { |resource| resource.send(attribute) },
|
77
|
+
options.presence || {})
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
nav data-controller="pagination"
|
2
|
+
ul.pagination.m-0.p-0
|
3
|
+
li.page-item class="#{paginated_resources.previous_page ? '' : 'disabled'}"
|
4
|
+
- if paginated_resources.previous_page
|
5
|
+
/= helpers.link_to page_path(paginated_resources.previous_page),
|
6
|
+
class: 'page-link',
|
7
|
+
data: { action: 'click->pagination#paginate',
|
8
|
+
resource_path: page_path(paginated_resources.previous_page) } do
|
9
|
+
a.page-link [href=page_path(paginated_resources.previous_page)
|
10
|
+
data-action="click->pagination#paginate"
|
11
|
+
data-resource-path=page_path(paginated_resources.previous_page)]
|
12
|
+
'←
|
13
|
+
- else
|
14
|
+
span.page-link ←
|
15
|
+
|
16
|
+
- limited_pages.each do |page|
|
17
|
+
- if page == paginated_resources.current_page
|
18
|
+
li.page-item.active
|
19
|
+
span.page-link = page
|
20
|
+
- else
|
21
|
+
li.page-item
|
22
|
+
/= helpers.link_to page_path(page),
|
23
|
+
class: 'page-link',
|
24
|
+
data: { action: 'click->pagination#paginate',
|
25
|
+
resource_path: page_path(page) } do
|
26
|
+
a.page-link [href=page_path(page)
|
27
|
+
data-action="click->pagination#paginate"
|
28
|
+
data-resource-path=page_path(page)]
|
29
|
+
= page
|
30
|
+
|
31
|
+
li.page-item class="#{paginated_resources.next_page ? '' : 'disabled'}"
|
32
|
+
- if paginated_resources.next_page
|
33
|
+
/= helpers.link_to page_path(paginated_resources.next_page),
|
34
|
+
class: 'page-link',
|
35
|
+
data: { action: 'click->pagination#paginate',
|
36
|
+
resource_path: page_path(paginated_resources.next_page) } do
|
37
|
+
a.page-link [href=page_path(paginated_resources.next_page)
|
38
|
+
data-action="click->pagination#paginate"
|
39
|
+
data-resource-path=page_path(paginated_resources.next_page)]
|
40
|
+
'→
|
41
|
+
- else
|
42
|
+
span.page-link →
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources
|
4
|
+
class PaginationComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
LIMIT = 10
|
6
|
+
|
7
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
8
|
+
include FlexiAdmin::Components::Helpers::UrlHelper
|
9
|
+
|
10
|
+
attr_reader :context, :per_page, :page, :limited_pagination
|
11
|
+
|
12
|
+
def initialize(context, per_page:, page:)
|
13
|
+
@context = context
|
14
|
+
@resources = context.resources
|
15
|
+
@parent = context.parent
|
16
|
+
@per_page = per_page
|
17
|
+
@page = page&.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
def render?
|
21
|
+
paginated_resources.total_pages > 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def limited_pages
|
25
|
+
return (1..paginated_resources.total_pages).to_a if paginated_resources.total_pages < LIMIT
|
26
|
+
|
27
|
+
max = paginated_resources.total_pages
|
28
|
+
|
29
|
+
mid_range_start = if page > (LIMIT / 2) && page < (max - (LIMIT / 2))
|
30
|
+
page - (LIMIT / 2)
|
31
|
+
elsif page < (LIMIT / 2)
|
32
|
+
1
|
33
|
+
else
|
34
|
+
max - LIMIT
|
35
|
+
end
|
36
|
+
|
37
|
+
mid_range_end = if page > (LIMIT / 2) && page < (max - (LIMIT / 2))
|
38
|
+
page + (LIMIT / 2)
|
39
|
+
elsif page < (LIMIT / 2)
|
40
|
+
LIMIT
|
41
|
+
else
|
42
|
+
max
|
43
|
+
end
|
44
|
+
|
45
|
+
[1, (mid_range_start..mid_range_end).to_a, max].flatten.compact.uniq
|
46
|
+
end
|
47
|
+
|
48
|
+
def page_path(page_number)
|
49
|
+
params = context.params
|
50
|
+
.merge(page: page_number, per_page:, frame: context.scope)
|
51
|
+
.to_params
|
52
|
+
|
53
|
+
resources_path(**params.merge)
|
54
|
+
end
|
55
|
+
|
56
|
+
def paginated_resources
|
57
|
+
@resources.paginate(page:, per_page:)
|
58
|
+
end
|
59
|
+
|
60
|
+
def total_pages
|
61
|
+
(resources.count / per_page.to_f).ceil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources
|
4
|
+
class ResourcesComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
include FlexiAdmin::Components::Helpers::ActionHelper
|
6
|
+
|
7
|
+
attr_reader :resources, :scope, :options, :title, :context_params
|
8
|
+
|
9
|
+
renders_one :actions
|
10
|
+
renders_one :views
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :views, :scope, :includes
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(resources, context_params:, views: nil, title: nil, **options)
|
17
|
+
@resources = resources
|
18
|
+
@scope = self.class.scope
|
19
|
+
@options = options
|
20
|
+
@options[:views] = views if views.present?
|
21
|
+
@context_params = context_params
|
22
|
+
@title = title
|
23
|
+
end
|
24
|
+
|
25
|
+
def context
|
26
|
+
options = @options.merge(title:,
|
27
|
+
views: @options[:views].presence || self.class.views)
|
28
|
+
|
29
|
+
context_params_with_parent = context_params.with_parent(options[:parent])
|
30
|
+
|
31
|
+
@context ||= FlexiAdmin::Models::Resources::Context.new(resources, scope, context_params_with_parent, options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.btn-group role="group"
|
2
|
+
- if list_view_available?
|
3
|
+
- path = resources_path(**context.params.merge(view: 'list', scope: context.scope, frame: context.scope).to_params)
|
4
|
+
.btn.btn-primary.opacity-75 [class="#{list_class}"
|
5
|
+
data-controller="switch-view"
|
6
|
+
data-action="click->switch-view#switch"
|
7
|
+
data-switch-view-resource-path-value="#{path}"]
|
8
|
+
i.bi.bi-list-ul
|
9
|
+
|
10
|
+
- if grid_view_available?
|
11
|
+
- path = resources_path(**context.params.merge(view: 'grid', scope: context.scope, frame: context.scope).to_params)
|
12
|
+
.btn.btn-primary.opacity-75 [class="#{grid_class}"
|
13
|
+
data-controller="switch-view"
|
14
|
+
data-action="click->switch-view#switch"
|
15
|
+
data-switch-view-resource-path-value="#{path}"]
|
16
|
+
i.bi.bi-grid
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Independent component.
|
4
|
+
module FlexiAdmin::Components::Resources
|
5
|
+
class SwitchViewComponent < FlexiAdmin::Components::BaseComponent
|
6
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
7
|
+
|
8
|
+
attr_reader :views, :context
|
9
|
+
|
10
|
+
def initialize(context)
|
11
|
+
@context = context
|
12
|
+
@views = context.views.presence || %w[list]
|
13
|
+
end
|
14
|
+
|
15
|
+
def render?
|
16
|
+
views.size > 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def list_view_available?
|
20
|
+
views.include?("list")
|
21
|
+
end
|
22
|
+
|
23
|
+
def grid_view_available?
|
24
|
+
views.include?("grid")
|
25
|
+
end
|
26
|
+
|
27
|
+
def list_class
|
28
|
+
if context.params.current_view == "list" ||
|
29
|
+
(context.views.first == "list" && context.params.current_view.blank?)
|
30
|
+
"active"
|
31
|
+
else
|
32
|
+
"bg-white text-dark"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def grid_class
|
37
|
+
if context.params.current_view == "grid" ||
|
38
|
+
(context.views.first == "grid" && context.params.current_view.blank?)
|
39
|
+
"active"
|
40
|
+
else
|
41
|
+
"bg-white text-dark"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
turbo-frame [id="#{context.scope}"
|
2
|
+
data-controller="bulk-action"
|
3
|
+
data-bulk-action-scope-value="#{context.scope}"]
|
4
|
+
= helpers.turbo_frame_tag "modalx_#{context.scope}", 'data-turbo-temporary': true
|
5
|
+
.h2 = title
|
6
|
+
.py-2.d-flex.justify-content-between.align-items-center
|
7
|
+
.d-flex.gap-3
|
8
|
+
= actions
|
9
|
+
- if context.paginate?
|
10
|
+
= render FlexiAdmin::Components::Resources::PaginationComponent.new(context, per_page: context.params.per_page, page: context.params.page)
|
11
|
+
.py-2
|
12
|
+
= views
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Resources
|
4
|
+
class ViewComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
attr_reader :context, :title
|
6
|
+
|
7
|
+
renders_one :actions
|
8
|
+
renders_one :views
|
9
|
+
|
10
|
+
def initialize(context)
|
11
|
+
@context = context
|
12
|
+
@title = context.options[:title]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
- if results.size.positive?
|
2
|
+
- results.each do |result|
|
3
|
+
li [data-action="#{data_action}"
|
4
|
+
data-autocomplete-resource-id-value="#{result.try(:id)}"]
|
5
|
+
- if action == 'show'
|
6
|
+
/= helpers.link_to main_app.send(path, result.id), class: 'text-primary text-decoration-none' do
|
7
|
+
a.text-primary.text-decoration-none href="#{main_app.send(path, result.id)}"
|
8
|
+
= value(result)
|
9
|
+
- else
|
10
|
+
= value(result)
|
11
|
+
- if autocomplete? && results_count > 100
|
12
|
+
li.text-muted zobrazeno 10 z #{results_count} výsledků
|
13
|
+
|
14
|
+
- if results.empty? && autocomplete?
|
15
|
+
li žádné výsledky hledání
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Components::Shared::Autocomplete
|
4
|
+
class ResultsComponent < FlexiAdmin::Components::BaseComponent
|
5
|
+
attr_reader :results, :results_count, :context_params, :fields, :action, :path
|
6
|
+
|
7
|
+
def initialize(results:, context_params:, results_count: nil)
|
8
|
+
@results = results
|
9
|
+
@results_count = results_count
|
10
|
+
@context_params = context_params
|
11
|
+
@action = context_params.params["ac_action"]
|
12
|
+
@fields = context_params.params["ac_fields"]
|
13
|
+
@path = context_params.params["ac_path"]
|
14
|
+
|
15
|
+
raise "Action not defined" unless @action
|
16
|
+
raise "Fields not defined" unless @fields
|
17
|
+
raise "Path is required for show action" if action == "show" && !@path
|
18
|
+
return unless results.present? && autocomplete? && fields.any? do |field|
|
19
|
+
!results.first.respond_to?(field.to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
raise "Field #{fields} not found on #{results.first.class.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def data_action
|
26
|
+
case action
|
27
|
+
when "select"
|
28
|
+
"click->autocomplete#select"
|
29
|
+
when "input"
|
30
|
+
"click->autocomplete#inputValue"
|
31
|
+
else
|
32
|
+
""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def value(result)
|
37
|
+
return result if datalist?
|
38
|
+
|
39
|
+
fields.map { |field| result.try(field) }.join(" - ")
|
40
|
+
end
|
41
|
+
|
42
|
+
def datalist?
|
43
|
+
action == "input"
|
44
|
+
end
|
45
|
+
|
46
|
+
def autocomplete?
|
47
|
+
action != "input"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
.autocomplete [data-controller="datalistx"
|
2
|
+
data-datalist-search-path-value="#{datalist_path(action:, attribute: :description)}"]
|
3
|
+
.input-group
|
4
|
+
.input-group-text id="button-addon1"
|
5
|
+
i.bi.bi-search
|
6
|
+
input [type="text"
|
7
|
+
name="datalist"
|
8
|
+
list="#{scope}_datalist"
|
9
|
+
class="form-control"
|
10
|
+
placeholder="hledat"
|
11
|
+
data-datalist-target="input"
|
12
|
+
data-action="keyup->datalist#keyup"
|
13
|
+
data-is-disabled="#{disabled}"
|
14
|
+
value="#{resource&.ac_title}"]
|
15
|
+
datalist [id="#{scope}_datalist" data-datalist-target="datalist"]
|
16
|
+
option value="This is a test"
|
17
|
+
input [type="hidden"
|
18
|
+
name="#{resource_input_name}"
|
19
|
+
data-datalist-target="resourceId"
|
20
|
+
value="#{resource&.id}"]
|
21
|
+
.clear-icon.d-none data-datalist-target="clearIcon" data-action="click->autocomplete#clear"
|
22
|
+
i.bi.bi-x-circle.me-2
|
23
|
+
.loading-icon.d-none data-datalist-target="loadingIcon"
|
24
|
+
.icon
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Independent component.
|
4
|
+
|
5
|
+
module FlexiAdmin::Components::Shared
|
6
|
+
class DatalistComponent < FlexiAdmin::Components::BaseComponent
|
7
|
+
include FlexiAdmin::Components::Helpers::ResourceHelper
|
8
|
+
|
9
|
+
attr_reader :resource, :disabled, :action, :parent
|
10
|
+
|
11
|
+
def initialize(resource = nil, scope: nil, disabled: false, parent: nil)
|
12
|
+
@resource = resource
|
13
|
+
@scope = scope
|
14
|
+
@parent = parent
|
15
|
+
|
16
|
+
@action = action
|
17
|
+
@disabled = disabled
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Independent component.
|
4
|
+
|
5
|
+
module FlexiAdmin::Components::Shared
|
6
|
+
class LinkComponent < FlexiAdmin::Components::BaseComponent
|
7
|
+
attr_reader :title, :path, :options
|
8
|
+
|
9
|
+
def initialize(title, path, **options)
|
10
|
+
@title = title
|
11
|
+
@path = path
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|