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.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +42 -0
  3. data/Rakefile +7 -0
  4. data/lib/flexi_admin/components/actions/checkbox_component.html.slim +8 -0
  5. data/lib/flexi_admin/components/actions/checkbox_component.rb +13 -0
  6. data/lib/flexi_admin/components/actions/select_component.html.slim +11 -0
  7. data/lib/flexi_admin/components/actions/select_component.rb +17 -0
  8. data/lib/flexi_admin/components/base_component.rb +19 -0
  9. data/lib/flexi_admin/components/form/field_component.rb +11 -0
  10. data/lib/flexi_admin/components/form/label_component.html.slim +2 -0
  11. data/lib/flexi_admin/components/form/label_component.rb +13 -0
  12. data/lib/flexi_admin/components/form/rows_component.rb +9 -0
  13. data/lib/flexi_admin/components/form/text_input_component.html.slim +5 -0
  14. data/lib/flexi_admin/components/form/text_input_component.rb +17 -0
  15. data/lib/flexi_admin/components/helpers/action_button_helper.rb +28 -0
  16. data/lib/flexi_admin/components/helpers/action_helper.rb +12 -0
  17. data/lib/flexi_admin/components/helpers/icon_helper.rb +11 -0
  18. data/lib/flexi_admin/components/helpers/link_helper.rb +8 -0
  19. data/lib/flexi_admin/components/helpers/resource_helper.rb +71 -0
  20. data/lib/flexi_admin/components/helpers/selectable.rb +11 -0
  21. data/lib/flexi_admin/components/helpers/url_helper.rb +8 -0
  22. data/lib/flexi_admin/components/helpers/value_formatter.rb +32 -0
  23. data/lib/flexi_admin/components/nav/floating_toc_component.html.slim +2 -0
  24. data/lib/flexi_admin/components/nav/floating_toc_component.rb +6 -0
  25. data/lib/flexi_admin/components/resource/autocomplete_component.html.slim +30 -0
  26. data/lib/flexi_admin/components/resource/autocomplete_component.rb +83 -0
  27. data/lib/flexi_admin/components/resource/button_select_component.html.slim +13 -0
  28. data/lib/flexi_admin/components/resource/button_select_component.rb +19 -0
  29. data/lib/flexi_admin/components/resource/form_component.rb +18 -0
  30. data/lib/flexi_admin/components/resource/form_element_component.html.slim +3 -0
  31. data/lib/flexi_admin/components/resource/form_element_component.rb +31 -0
  32. data/lib/flexi_admin/components/resource/form_mixin.rb +287 -0
  33. data/lib/flexi_admin/components/resource/link_action_component.html.slim +8 -0
  34. data/lib/flexi_admin/components/resource/link_action_component.rb +16 -0
  35. data/lib/flexi_admin/components/resource/show_page_component.rb +21 -0
  36. data/lib/flexi_admin/components/resource/view_component.html.slim +26 -0
  37. data/lib/flexi_admin/components/resource/view_component.rb +22 -0
  38. data/lib/flexi_admin/components/resources/bulk_action/button_component.html.slim +7 -0
  39. data/lib/flexi_admin/components/resources/bulk_action/button_component.rb +29 -0
  40. data/lib/flexi_admin/components/resources/bulk_action/modal_component.html.slim +32 -0
  41. data/lib/flexi_admin/components/resources/bulk_action/modal_component.rb +54 -0
  42. data/lib/flexi_admin/components/resources/grid_view/card_component.html.slim +18 -0
  43. data/lib/flexi_admin/components/resources/grid_view/card_component.rb +65 -0
  44. data/lib/flexi_admin/components/resources/grid_view/grid_component.html.slim +10 -0
  45. data/lib/flexi_admin/components/resources/grid_view/grid_component.rb +16 -0
  46. data/lib/flexi_admin/components/resources/grid_view_component.rb +89 -0
  47. data/lib/flexi_admin/components/resources/index_page_component.html.slim +13 -0
  48. data/lib/flexi_admin/components/resources/index_page_component.rb +19 -0
  49. data/lib/flexi_admin/components/resources/list_view/cell_component.html.slim +2 -0
  50. data/lib/flexi_admin/components/resources/list_view/cell_component.rb +26 -0
  51. data/lib/flexi_admin/components/resources/list_view/table_component.html.slim +17 -0
  52. data/lib/flexi_admin/components/resources/list_view/table_component.rb +21 -0
  53. data/lib/flexi_admin/components/resources/list_view_component.rb +80 -0
  54. data/lib/flexi_admin/components/resources/pagination_component.html.slim +42 -0
  55. data/lib/flexi_admin/components/resources/pagination_component.rb +64 -0
  56. data/lib/flexi_admin/components/resources/resources_component.rb +34 -0
  57. data/lib/flexi_admin/components/resources/switch_view_component.html.slim +16 -0
  58. data/lib/flexi_admin/components/resources/switch_view_component.rb +45 -0
  59. data/lib/flexi_admin/components/resources/view_component.html.slim +12 -0
  60. data/lib/flexi_admin/components/resources/view_component.rb +15 -0
  61. data/lib/flexi_admin/components/shared/alert_component.html.slim +2 -0
  62. data/lib/flexi_admin/components/shared/alert_component.rb +11 -0
  63. data/lib/flexi_admin/components/shared/autocomplete/results_component.html.slim +15 -0
  64. data/lib/flexi_admin/components/shared/autocomplete/results_component.rb +50 -0
  65. data/lib/flexi_admin/components/shared/autocomplete.rb +6 -0
  66. data/lib/flexi_admin/components/shared/datalist_component.html.slim +24 -0
  67. data/lib/flexi_admin/components/shared/datalist_component.rb +20 -0
  68. data/lib/flexi_admin/components/shared/link_component.html.slim +3 -0
  69. data/lib/flexi_admin/components/shared/link_component.rb +15 -0
  70. data/lib/flexi_admin/components/shared/medium_component.html.slim +7 -0
  71. data/lib/flexi_admin/components/shared/medium_component.rb +51 -0
  72. data/lib/flexi_admin/components/shared/table/header_item_component.html.slim +9 -0
  73. data/lib/flexi_admin/components/shared/table/header_item_component.rb +78 -0
  74. data/lib/flexi_admin/components/shared/trix_component.html.slim +22 -0
  75. data/lib/flexi_admin/components/shared/trix_component.rb +21 -0
  76. data/lib/flexi_admin/components.rb +87 -0
  77. data/lib/flexi_admin/config.rb +24 -0
  78. data/lib/flexi_admin/controllers/modals_controller.rb +13 -0
  79. data/lib/flexi_admin/controllers/resources_controller.rb +240 -0
  80. data/lib/flexi_admin/controllers.rb +9 -0
  81. data/lib/flexi_admin/engine.rb +34 -0
  82. data/lib/flexi_admin/helpers/application_helper.rb +4 -0
  83. data/lib/flexi_admin/helpers.rb +8 -0
  84. data/lib/flexi_admin/javascript/controllers/application.js +9 -0
  85. data/lib/flexi_admin/javascript/controllers/autocomplete_controller.js +142 -0
  86. data/lib/flexi_admin/javascript/controllers/bulk_action_controller.js +158 -0
  87. data/lib/flexi_admin/javascript/controllers/button_select_controller.js +32 -0
  88. data/lib/flexi_admin/javascript/controllers/datalist_controller.js +104 -0
  89. data/lib/flexi_admin/javascript/controllers/floating_toc_controller.js +39 -0
  90. data/lib/flexi_admin/javascript/controllers/form_controller.js +17 -0
  91. data/lib/flexi_admin/javascript/controllers/form_validation_controller.js +86 -0
  92. data/lib/flexi_admin/javascript/controllers/index.js +44 -0
  93. data/lib/flexi_admin/javascript/controllers/pagination_controller.js +13 -0
  94. data/lib/flexi_admin/javascript/controllers/sorting_controller.js +17 -0
  95. data/lib/flexi_admin/javascript/controllers/switch_view_controller.js +15 -0
  96. data/lib/flexi_admin/javascript/controllers/toast_controller.js +18 -0
  97. data/lib/flexi_admin/javascript/controllers/trix_controller.js +32 -0
  98. data/lib/flexi_admin/javascript/controllers/uploads_controller.js +164 -0
  99. data/lib/flexi_admin/javascript/flexi_admin.js +4 -0
  100. data/lib/flexi_admin/javascript/utils.js +26 -0
  101. data/lib/flexi_admin/models/concerns/application_resource.rb +25 -0
  102. data/lib/flexi_admin/models/concerns/parentable.rb +17 -0
  103. data/lib/flexi_admin/models/context_params.rb +127 -0
  104. data/lib/flexi_admin/models/resources/context.rb +59 -0
  105. data/lib/flexi_admin/models/struct.rb +29 -0
  106. data/lib/flexi_admin/models/toast.rb +23 -0
  107. data/lib/flexi_admin/models.rb +20 -0
  108. data/lib/flexi_admin/prompts/codegen-system-prompt.md +50 -0
  109. data/lib/flexi_admin/railtie.rb +78 -0
  110. data/lib/flexi_admin/routes.rb +15 -0
  111. data/lib/flexi_admin/services/code_gen/code_export.rb +22 -0
  112. data/lib/flexi_admin/services/code_gen/gemini.rb +104 -0
  113. data/lib/flexi_admin/services/code_gen/gpt.rb +68 -0
  114. data/lib/flexi_admin/services/code_gen/runner.rb +210 -0
  115. data/lib/flexi_admin/services/code_gen.rb +14 -0
  116. data/lib/flexi_admin/services/create_resource.rb +32 -0
  117. data/lib/flexi_admin/services/update_resource.rb +30 -0
  118. data/lib/flexi_admin/services.rb +10 -0
  119. data/lib/flexi_admin/version.rb +10 -0
  120. data/lib/flexi_admin/views/shared/_redirect.slim +2 -0
  121. data/lib/flexi_admin/views/shared/_reload.slim +2 -0
  122. data/lib/flexi_admin/views/shared/_toasts.slim +15 -0
  123. data/lib/flexi_admin/views/shared/not_authorized.slim +11 -0
  124. data/lib/flexi_admin.rb +58 -0
  125. data/lib/tasks/flexi_admin.rake +49 -0
  126. data/lib/tasks/semantic.rake +57 -0
  127. 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,13 @@
1
+ h1 = title
2
+ - if subtitle
3
+ span.text-muted = subtitle
4
+
5
+ div data-scope="#{scope}"
6
+ div.py-3
7
+ .d-flex.justify-content-between
8
+ - if show_search
9
+ div style="width: 330px"
10
+ = search
11
+ div
12
+ = actions
13
+ = content
@@ -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,2 @@
1
+ div class="#{merged_classes}"
2
+ = value
@@ -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,2 @@
1
+ .alert.alert-success role="alert"
2
+ = message
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin::Components::Shared
4
+ class AlertComponent < FlexiAdmin::Components::BaseComponent
5
+ attr_reader :message
6
+
7
+ def initialize(message:)
8
+ @message = message
9
+ end
10
+ end
11
+ 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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "autocomplete/results_component"
4
+
5
+ module FlexiAdmin::Components::Shared::Autocomplete
6
+ 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,3 @@
1
+ a href="#{path}" class="#{options[:class]}" style="#{options[:style]}"
2
+ = title
3
+ = content
@@ -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