katalyst-tables 3.0.0.beta1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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