Skip to content

Commit a17cc98

Browse files
committed
Adds DataTable per-row class and data hooks
Downstream tables mark rows with state-derived classes and data attributes, which row_id alone cannot express.
1 parent 1b74977 commit a17cc98

3 files changed

Lines changed: 58 additions & 6 deletions

File tree

.changeset/data-table-row-hooks.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@openproject/primer-view-components": minor
3+
---
4+
5+
`DataTable`: accepts `row_classes:` and `row_data:` procs, called with each row, so consumers can attach per-row CSS classes and data attributes to the rendered `<tr>`

app/components/primer/open_project/data_table.rb

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ def sort_data
136136
# @param row_dom_id [Boolean]
137137
# Whether each `<tr>` additionally gets a DOM `id`, namespaced by the
138138
# table id to stay unique across tables. Requires `row_id`.
139+
# @param row_classes [Proc, nil]
140+
# Optional `->(row)` returning extra CSS classes for the row's `<tr>`.
141+
# @param row_data [Proc, nil]
142+
# Optional `->(row)` returning a Hash of data attributes for the row's `<tr>`.
139143
# @param html_data [Hash]
140144
# HTML data attributes to be passed to the table
141145
# @param system_arguments [Hash]
@@ -150,6 +154,8 @@ def initialize(
150154
divider: false,
151155
row_id: nil,
152156
row_dom_id: false,
157+
row_classes: nil,
158+
row_data: nil,
153159
html_data: {},
154160
**system_arguments
155161
)
@@ -161,6 +167,8 @@ def initialize(
161167
@sort_href_builder = sort_href_builder
162168
@divider = fetch_or_fallback_boolean(divider, false)
163169
@row_id_proc = row_id
170+
@row_classes_proc = row_classes
171+
@row_data_proc = row_data
164172
@row_dom_id = fetch_or_fallback_boolean(row_dom_id, false)
165173
raise ArgumentError, "`row_dom_id` requires a `row_id` proc" if @row_dom_id && @row_id_proc.nil?
166174
@id = system_arguments[:id] ||= self.class.generate_id(base_name: "data-table")
@@ -349,14 +357,19 @@ def grid_template_from_columns(columns)
349357
end
350358

351359
def row_arguments(row)
352-
arguments = { classes: "TableRow" }
353-
return arguments unless @row_id_proc
360+
arguments = { classes: class_names("TableRow", @row_classes_proc&.call(row)) }
354361

355-
value = @row_id_proc.call(row).to_s
356-
return arguments if value.blank?
362+
data = (@row_data_proc&.call(row) || {}).to_h
357363

358-
arguments[:data] = { row_id: value }
359-
arguments[:id] = "#{@id}-row-#{value}" if @row_dom_id
364+
if @row_id_proc
365+
value = @row_id_proc.call(row).to_s
366+
if value.present?
367+
data = data.merge(row_id: value)
368+
arguments[:id] = "#{@id}-row-#{value}" if @row_dom_id
369+
end
370+
end
371+
372+
arguments[:data] = data if data.any?
360373
arguments
361374
end
362375

test/components/primer/open_project/data_table/data_table_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,40 @@ def test_cell_data_does_not_displace_sort_metadata
730730
assert_selector(".TableCell[data-sort-value='First'][data-extra='yes']")
731731
end
732732

733+
def test_applies_row_classes_from_the_proc
734+
render_component(@data, row_classes: ->(row) { "row-#{row.id}" }) do |table|
735+
table.with_column(field: :subject, header: "Subject")
736+
end
737+
738+
assert_selector(".TableBody .TableRow.row-1")
739+
assert_selector(".TableBody .TableRow.row-3")
740+
end
741+
742+
def test_applies_row_data_from_the_proc
743+
render_component(@data, row_data: ->(row) { { subject_slug: row.subject.downcase } }) do |table|
744+
table.with_column(field: :subject, header: "Subject")
745+
end
746+
747+
assert_selector(".TableRow[data-subject-slug='first']")
748+
end
749+
750+
def test_row_data_coexists_with_row_id
751+
render_component(@data, row_id: ->(row) { row.id }, row_data: ->(_row) { { extra: "yes" } }) do |table|
752+
table.with_column(field: :subject, header: "Subject")
753+
end
754+
755+
assert_selector(".TableRow[data-row-id='1'][data-extra='yes']")
756+
end
757+
758+
def test_row_hooks_are_optional
759+
render_component(@data) do |table|
760+
table.with_column(field: :subject, header: "Subject")
761+
end
762+
763+
assert_selector(".TableBody .TableRow", count: 3)
764+
refute_selector(".TableBody .TableRow[data-row-id]")
765+
end
766+
733767
private
734768

735769
def body_first_column_texts

0 commit comments

Comments
 (0)