katalyst-tables 3.0.0.beta1 → 3.0.0

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -2
  3. data/README.md +56 -190
  4. data/app/assets/builds/katalyst/tables.esm.js +17 -47
  5. data/app/assets/builds/katalyst/tables.js +17 -47
  6. data/app/assets/builds/katalyst/tables.min.js +1 -1
  7. data/app/assets/builds/katalyst/tables.min.js.map +1 -1
  8. data/app/components/concerns/katalyst/tables/has_table_content.rb +17 -8
  9. data/app/components/concerns/katalyst/tables/identifiable.rb +51 -0
  10. data/app/components/concerns/katalyst/tables/orderable.rb +35 -105
  11. data/app/components/concerns/katalyst/tables/selectable.rb +18 -75
  12. data/app/components/concerns/katalyst/tables/sortable.rb +51 -17
  13. data/app/components/katalyst/table_component.html.erb +4 -4
  14. data/app/components/katalyst/table_component.rb +271 -53
  15. data/app/components/katalyst/tables/body_row_component.html.erb +5 -0
  16. data/app/components/katalyst/tables/body_row_component.rb +4 -31
  17. data/app/components/katalyst/tables/cell_component.rb +85 -0
  18. data/app/components/katalyst/tables/{body → cells}/boolean_component.rb +8 -2
  19. data/app/components/katalyst/tables/{body → cells}/currency_component.rb +7 -7
  20. data/app/components/katalyst/tables/{body → cells}/date_component.rb +12 -9
  21. data/app/components/katalyst/tables/{body → cells}/date_time_component.rb +13 -10
  22. data/app/components/katalyst/tables/{body → cells}/number_component.rb +5 -5
  23. data/app/components/katalyst/tables/cells/ordinal_component.rb +44 -0
  24. data/app/components/katalyst/tables/{body → cells}/rich_text_component.rb +8 -5
  25. data/app/components/katalyst/tables/cells/select_component.rb +39 -0
  26. data/app/components/katalyst/tables/data.rb +30 -0
  27. data/app/components/katalyst/tables/header_row_component.html.erb +5 -0
  28. data/app/components/katalyst/tables/header_row_component.rb +4 -25
  29. data/app/components/katalyst/tables/label.rb +37 -0
  30. data/app/components/katalyst/tables/orderable/form_component.rb +38 -0
  31. data/app/components/katalyst/tables/selectable/form_component.html.erb +3 -3
  32. data/app/components/katalyst/tables/selectable/form_component.rb +8 -11
  33. data/app/controllers/concerns/katalyst/tables/backend.rb +2 -28
  34. data/app/helpers/katalyst/tables/frontend.rb +48 -2
  35. data/app/javascript/tables/application.js +0 -5
  36. data/app/javascript/tables/orderable/form_controller.js +8 -6
  37. data/app/javascript/tables/orderable/item_controller.js +9 -0
  38. data/app/models/concerns/katalyst/tables/collection/core.rb +6 -1
  39. data/app/models/concerns/katalyst/tables/collection/sorting.rb +85 -17
  40. data/app/models/katalyst/tables/collection/array.rb +38 -0
  41. data/app/models/katalyst/tables/collection/base.rb +4 -0
  42. data/config/locales/tables.en.yml +0 -6
  43. data/lib/katalyst/tables/config.rb +23 -0
  44. data/lib/katalyst/tables.rb +9 -0
  45. metadata +22 -29
  46. data/app/components/concerns/katalyst/tables/body/typed_columns.rb +0 -132
  47. data/app/components/concerns/katalyst/tables/configurable_component.rb +0 -52
  48. data/app/components/concerns/katalyst/tables/header/typed_columns.rb +0 -179
  49. data/app/components/katalyst/tables/body/attachment_component.rb +0 -58
  50. data/app/components/katalyst/tables/body/link_component.rb +0 -40
  51. data/app/components/katalyst/tables/body_cell_component.rb +0 -55
  52. data/app/components/katalyst/tables/header/attachment_component.rb +0 -15
  53. data/app/components/katalyst/tables/header/boolean_component.rb +0 -15
  54. data/app/components/katalyst/tables/header/currency_component.rb +0 -15
  55. data/app/components/katalyst/tables/header/date_component.rb +0 -15
  56. data/app/components/katalyst/tables/header/date_time_component.rb +0 -15
  57. data/app/components/katalyst/tables/header/link_component.rb +0 -15
  58. data/app/components/katalyst/tables/header/number_component.rb +0 -15
  59. data/app/components/katalyst/tables/header/rich_text_component.rb +0 -15
  60. data/app/components/katalyst/tables/header_cell_component.rb +0 -97
  61. data/app/helpers/katalyst/tables/frontend/helper.rb +0 -31
  62. data/app/javascript/tables/turbo/collection_controller.js +0 -38
  63. data/app/models/katalyst/tables/collection/sort_form.rb +0 -120
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Body
8
- # Displays a link to the record
9
- # The link text is the value of the attribute
10
- # @see Koi::Tables::BodyRowComponent#link
11
- class LinkComponent < BodyCellComponent
12
- def initialize(table, record, attribute, url:, link: {}, **options)
13
- super(table, record, attribute, **options)
14
-
15
- @url = url
16
- @link_options = link
17
- end
18
-
19
- def call
20
- content # ensure content is set before rendering options
21
-
22
- link = content.present? && url.present? ? link_to(content, url, @link_options) : content.to_s
23
- content_tag(@type, link, **html_attributes)
24
- end
25
-
26
- def url
27
- case @url
28
- when Symbol
29
- # helpers are not available until the component is rendered
30
- @url = helpers.public_send(@url, record)
31
- when Proc
32
- @url = @url.call(record)
33
- else
34
- @url
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- class BodyCellComponent < ViewComponent::Base # :nodoc:
6
- include Katalyst::HtmlAttributes
7
-
8
- attr_reader :record
9
-
10
- def initialize(table, record, attribute, heading: false, **html_attributes)
11
- super(**html_attributes)
12
-
13
- @table = table
14
- @record = record
15
- @attribute = attribute
16
- @type = heading ? :th : :td
17
- end
18
-
19
- def before_render
20
- # fallback if no content block is given
21
- with_content(rendered_value) unless content?
22
- end
23
-
24
- def call
25
- content # ensure content is set before rendering options
26
-
27
- content_tag(@type, content, **html_attributes)
28
- end
29
-
30
- # @return the object for this row.
31
- def object
32
- @record
33
- end
34
-
35
- def value
36
- @record.public_send(@attribute)
37
- end
38
-
39
- def rendered_value
40
- value.to_s
41
- end
42
-
43
- def to_s
44
- value.to_s
45
- end
46
-
47
- def inspect
48
- "#<#{self.class.name} attribute: #{@attribute.inspect}, value: #{value.inspect}>"
49
- end
50
-
51
- # Backwards compatibility with tables 1.0
52
- alias_method :options, :html_attributes=
53
- end
54
- end
55
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class AttachmentComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-attachment")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class BooleanComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-boolean")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class CurrencyComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-currency")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class DateComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-date")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class DateTimeComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-datetime")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class LinkComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-link")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class NumberComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-number")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- module Header
8
- class RichTextComponent < HeaderCellComponent
9
- def default_html_attributes
10
- super.merge_html(class: "type-rich-text")
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- using Katalyst::HtmlAttributes::HasHtmlAttributes
4
-
5
- module Katalyst
6
- module Tables
7
- class HeaderCellComponent < ViewComponent::Base # :nodoc:
8
- include Frontend::Helper
9
- include Katalyst::HtmlAttributes
10
- include Sortable
11
-
12
- delegate :object_name, :collection, :sorting, to: :@table
13
-
14
- def initialize(table, attribute, label: nil, link: {}, width: nil, **html_attributes)
15
- super(**html_attributes)
16
-
17
- @table = table
18
- @attribute = attribute
19
- @value = label
20
- @width = width
21
- @link_attributes = link
22
- end
23
-
24
- def call
25
- tag.th(**html_attributes) do
26
- if sortable?(@attribute)
27
- link_to(value, sort_url(@attribute), **link_attributes)
28
- else
29
- value
30
- end
31
- end
32
- end
33
-
34
- def value
35
- if !@value.nil?
36
- @value
37
- elsif object_name.present?
38
- translation
39
- else
40
- default_value
41
- end
42
- end
43
-
44
- def translation(key = "activerecord.attributes.#{object_name}.#{@attribute}")
45
- translate(key, default: default_value)
46
- end
47
-
48
- def default_value
49
- @attribute.to_s.humanize.capitalize
50
- end
51
-
52
- def inspect
53
- "#<#{self.class.name} attribute: #{@attribute.inspect}, value: #{@value.inspect}>"
54
- end
55
-
56
- # Backwards compatibility with tables 1.0
57
- alias_method :options, :html_attributes=
58
-
59
- private
60
-
61
- def width_class
62
- case @width
63
- when :xs
64
- "width-xs"
65
- when :s
66
- "width-s"
67
- when :m
68
- "width-m"
69
- when :l
70
- "width-l"
71
- else
72
- ""
73
- end
74
- end
75
-
76
- def link_attributes
77
- { data: { turbo_action: "replace" } }.merge_html(@link_attributes)
78
- end
79
-
80
- def default_html_attributes
81
- sort_data.merge(width_data)
82
- end
83
-
84
- def width_data
85
- return {} unless @width
86
-
87
- { class: width_class }
88
- end
89
-
90
- def sort_data
91
- return {} unless sorting&.supports?(collection, @attribute)
92
-
93
- { data: { sort: sorting.status(@attribute) } }
94
- end
95
- end
96
- end
97
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- module Frontend
6
- # @deprecated Use {Katalyst::TableComponent} instead.
7
- module Helper # :nodoc:
8
- extend ActiveSupport::Concern
9
-
10
- # Generates a url for applying/toggling sort for the given column.
11
- #
12
- # @param sort [String, nil] sort parameter to apply, or nil to remove sorting
13
- # @return [String] URL for toggling column sorting
14
- # @deprecated Use {Katalyst::TablesComponent} instead.
15
- def sort_url_for(sort: nil, default: nil)
16
- # Implementation inspired by pagy's `pagy_url_for` helper.
17
- # Preserve any existing GET parameters
18
- # CAUTION: these parameters are not sanitised
19
- params = if sort && !sort.eql?(default)
20
- request.GET.merge("sort" => sort).except("page")
21
- else
22
- request.GET.except("page", "sort")
23
- end
24
- query_string = params.empty? ? "" : "?#{Rack::Utils.build_nested_query(params)}"
25
-
26
- "#{request.path}#{query_string}"
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,38 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus";
2
- import { Turbo } from "@hotwired/turbo-rails";
3
-
4
- export default class TurboCollectionController extends Controller {
5
- static values = {
6
- query: String,
7
- sort: String,
8
- };
9
-
10
- queryValueChanged(query) {
11
- Turbo.navigator.history.replace(this.#url(query));
12
- }
13
-
14
- sortValueChanged(sort) {
15
- document.querySelectorAll(this.#sortSelector).forEach((input) => {
16
- if (input) input.value = sort;
17
- });
18
- }
19
-
20
- get #sortSelector() {
21
- return "input[name='sort']";
22
- }
23
-
24
- #url(query) {
25
- const frame = this.element.closest("turbo-frame");
26
- let url;
27
-
28
- if (frame) {
29
- url = new URL(frame.baseURI);
30
- } else {
31
- url = new URL(window.location.href);
32
- }
33
-
34
- url.search = query;
35
-
36
- return url;
37
- }
38
- }
@@ -1,120 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Tables
5
- module Collection
6
- # A FormObject (model) representing the sort state of controller for a given
7
- # collection/parameter.
8
- class SortForm
9
- DIRECTIONS = %w[asc desc].freeze
10
-
11
- attr_accessor :column, :direction, :default
12
-
13
- def self.normalize(param)
14
- new(param:).to_param
15
- end
16
-
17
- def self.parse(param, **args)
18
- new(param:, **args)
19
- end
20
-
21
- def initialize(param: nil, column: nil, direction: nil, default: nil)
22
- if param.present?
23
- column, direction = param.to_s.split
24
- direction = "asc" unless DIRECTIONS.include?(direction)
25
- end
26
-
27
- self.column = column
28
- self.direction = direction
29
- self.default = SortForm.normalize(default) if default
30
- end
31
-
32
- def to_param
33
- "#{column} #{direction}"
34
- end
35
-
36
- def default?
37
- to_param == default.to_param
38
- end
39
-
40
- def hash
41
- to_param.hash
42
- end
43
-
44
- def eql?(other)
45
- to_param == other.to_param
46
- end
47
-
48
- alias to_s to_param
49
-
50
- # Returns true if the given collection supports sorting on the given
51
- # column. A column supports sorting if it is a database column or if
52
- # the collection responds to `order_by_#{column}(direction)`.
53
- #
54
- # @param collection [ActiveRecord::Relation]
55
- # @param column [String, Symbol]
56
- # @return [true, false]
57
- def supports?(collection, column)
58
- scope_for(collection).respond_to?(:"order_by_#{column}") ||
59
- model_for(collection).has_attribute?(column.to_s)
60
- end
61
-
62
- # Returns the current sort behaviour of the given column, for use as a
63
- # column heading class in the table view.
64
- #
65
- # @param column [String, Symbol] the table column as defined in table_with
66
- # @return [String] the current sort behaviour of the given column
67
- def status(column)
68
- direction if column.to_s == self.column
69
- end
70
-
71
- # Calculates the sort parameter to apply when the given column is toggled.
72
- #
73
- # @param column [String, Symbol]
74
- # @return [String]
75
- def toggle(column)
76
- return "#{column} asc" unless column.to_s == self.column
77
-
78
- case direction
79
- when "asc"
80
- "#{column} desc"
81
- when "desc"
82
- "#{column} asc"
83
- end
84
- end
85
-
86
- # Apply the constructed sort ordering to the collection.
87
- #
88
- # @param collection [ActiveRecord::Relation]
89
- # @return [Array(SortForm, ActiveRecord::Relation)]
90
- def apply(collection)
91
- return [self, collection] if column.nil?
92
-
93
- if collection.respond_to?(:"order_by_#{column}")
94
- collection = collection.reorder(nil).public_send(:"order_by_#{column}", direction.to_sym)
95
- elsif collection.model.has_attribute?(column)
96
- collection = collection.reorder(column => direction)
97
- else
98
- clear!
99
- end
100
-
101
- [self, collection]
102
- end
103
-
104
- private
105
-
106
- def clear!
107
- self.column = self.direction = nil
108
- end
109
-
110
- def scope_for(collection)
111
- collection.is_a?(Core) ? collection.items : collection
112
- end
113
-
114
- def model_for(collection)
115
- scope_for(collection).model
116
- end
117
- end
118
- end
119
- end
120
- end