Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PBNTR 783] AdvancedTable Rails: Subrow Headers #4088

Merged
merged 9 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@

<%= pb_rails("advanced_table", props: { table_data: @table_data, column_definitions: column_definitions }) do %>
<%= pb_rails("advanced_table/table_header", props: { column_definitions: column_definitions }) %>
<%= pb_rails("advanced_table/table_body", props: { id: "subrow_headers", table_data: @table_data, column_definitions: column_definitions, subrow_headers: subrow_headers, enable_toggle_expansion: "all" }) %>
<%= pb_rails("advanced_table/table_body", props: { id: "test_table", table_data: @table_data, column_definitions: column_definitions, subrow_headers: subrow_headers, enable_toggle_expansion: "all" }) %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
`subrow_headers` is an optional prop that if present will add header rows at each level of the nested data. The prop takes an array of strings, each string being the text for each header row. The array of strings must be in the order in which they need to be rendered in the UI according to depth.

`enable_toggle_expansion` is an additional optional prop that can be used in conjunction with the subRowHeaders prop. `enable_toggle_expansion` is a string that can be "all", "header" or "none". If set to "all", the toggle exapansion button will appear in the table header as well as in the subRow headers. If set to "header" button will only appear in header and NOT in subRow headers. This is set to "header" by default.
`enable_toggle_expansion` is an additional optional prop that can be used in conjunction with the subRowHeaders prop. `enable_toggle_expansion` is a string that can be "all", "header" or "none". If set to "all", the toggle expansion button will appear in the table header as well as in the subRow headers. If set to "header", the button will only appear in header and NOT in subRow headers. This prop is set to "header" by default.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
examples:
rails:
- advanced_table_beta: Default (Required Props)
# - advanced_table_beta_subrow_headers: SubRow Headers
- advanced_table_beta_subrow_headers: SubRow Headers
- advanced_table_collapsible_trail_rails: Collapsible Trail
- advanced_table_beta_sort: Enable Sorting
- advanced_table_custom_cell_rails: Custom Components for Cells
Expand Down
61 changes: 53 additions & 8 deletions playbook/app/pb_kits/playbook/pb_advanced_table/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
if (!dataContent) {
return;
}

// Split the dataContent to get all ancestor IDs, check against simpleExpandedRows
// Split the dataContent to get all ancestor IDs, check against ExpandedRows
const ancestorIds = dataContent.split("-").slice(0, -1);

const prefixedAncestorIds = ancestorIds.map(
Expand All @@ -76,7 +75,22 @@ export default class PbAdvancedTable extends PbEnhancedElement {
PbAdvancedTable.expandedRows.has(id)
);

if (allAncestorsExpanded) {
const checkIfParentIsExpanded = () => {
if (dataContent.endsWith("sr")) {
const parentRowId = childRow.dataset.rowParent;
const isParentVisible =
childRow.previousElementSibling.classList.contains("is-visible");
if (parentRowId) {
const isInSet = PbAdvancedTable.expandedRows.has(parentRowId);
if (isInSet && isParentVisible) {
return true;
}
}
}
return false;
};

if (allAncestorsExpanded || checkIfParentIsExpanded()) {
childRow.style.display = "table-row";
childRow.classList.add("is-visible");
} else {
Expand Down Expand Up @@ -143,7 +157,7 @@ export default class PbAdvancedTable extends PbEnhancedElement {
static handleToggleAllHeaders(element) {
const table = element.closest(".pb_table");
const firstLevelButtons = table.querySelectorAll(
".pb_advanced_table_body > .pb_table_tr [data-advanced-table]"
".pb_advanced_table_body > .pb_table_tr[data-row-depth='0'] [data-advanced-table]"
);

const allExpanded = Array.from(firstLevelButtons).every(
Expand Down Expand Up @@ -175,12 +189,43 @@ export default class PbAdvancedTable extends PbEnhancedElement {
}
}

// static handleToggleAllSubRows(element, rowDepth) {}
static handleToggleAllSubRows(element, rowDepth) {
const table = element.closest(".pb_table");
const parentRow = element.closest("tr");
if (!parentRow) {
return;
}
const rowParentId = parentRow.dataset.rowParent;
// Select all buttons that for subrows at that depth and with same rowParent
const subRowButtons = table.querySelectorAll(
`.pb_advanced_table_body > .pb_table_tr[data-row-depth='${rowDepth}'].pb_table_tr[data-row-parent='${rowParentId}'] [data-advanced-table]`
);

const allExpanded = Array.from(subRowButtons).every(
(button) =>
button.querySelector(UP_ARROW_SELECTOR).style.display === "inline-block"
);

if (allExpanded) {
subRowButtons.forEach((button) => {
button.click();
PbAdvancedTable.expandedRows.delete(button.id);
});
} else {
subRowButtons.forEach((button) => {
if (!PbAdvancedTable.expandedRows.has(button.id)) {
button.click();
PbAdvancedTable.expandedRows.add(button.id);
}
});
}
}
}

window.expandAllRows = (element) => {
PbAdvancedTable.handleToggleAllHeaders(element);
};
// window.expandAllSubRows = (element, rowDepth) => {
// PbAdvancedTable.handleToggleAllSubRows(element, rowDepth);
// };

window.expandAllSubRows = (element, rowDepth) => {
PbAdvancedTable.handleToggleAllSubRows(element, rowDepth);
};
41 changes: 23 additions & 18 deletions playbook/app/pb_kits/playbook/pb_advanced_table/table_body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,43 @@ def flatten_columns(columns)
end.compact
end

def render_row_and_children(row, column_definitions, current_depth, first_parent_child, ancestor_ids = [], top_parent_id = nil)
def render_row_and_children(row, column_definitions, current_depth, first_parent_child, ancestor_ids = [], top_parent_id = nil, additional_classes: "", table_data_attributes: {})
top_parent_id ||= row.object_id
new_ancestor_ids = ancestor_ids + [row.object_id]
leaf_columns = flatten_columns(column_definitions)

output = ActiveSupport::SafeBuffer.new
is_first_child_of_subrow = current_depth.positive? && first_parent_child && subrow_headers[current_depth - 1].present?

output << pb_rails("advanced_table/table_subrow_header", props: { row: row, column_definitions: column_definitions, depth: current_depth, subrow_header: subrow_headers[current_depth - 1], collapsible_trail: collapsible_trail }) if is_first_child_of_subrow && enable_toggle_expansion == "all"
subrow_ancestor_ids = ancestor_ids + ["#{row.object_id}sr"]
subrow_data_attributes = {
advanced_table_content: subrow_ancestor_ids.join("-"),
row_depth: current_depth,
row_parent: "#{id}_#{ancestor_ids.last}",
}
# Subrow header if applicable
output << pb_rails("advanced_table/table_subrow_header", props: { row: row, column_definitions: leaf_columns, depth: current_depth, subrow_header: subrow_headers[current_depth - 1], collapsible_trail: collapsible_trail, classname: "toggle-content", subrow_data_attributes: subrow_data_attributes }) if is_first_child_of_subrow && enable_toggle_expansion == "all"

# Pass only leaf_columns to table_row to account for multiple nested columns
output << pb_rails("advanced_table/table_row", props: {
id: id,
row: row,
column_definitions: leaf_columns,
depth: current_depth,
collapsible_trail: collapsible_trail,
})
current_data_attributes = current_depth.zero? ? { row_depth: 0 } : table_data_attributes

# Additional class and data attributes needed for toggle logic
output << pb_rails("advanced_table/table_row", props: { id: id, row: row, column_definitions: leaf_columns, depth: current_depth, collapsible_trail: collapsible_trail, classname: additional_classes, table_data_attributes: current_data_attributes })

if row[:children].present?
output << row[:children].map do |child_row|
row[:children].each do |child_row|
is_first_child = row[:children].first == child_row

child_output = render_row_and_children(child_row, column_definitions, current_depth + 1, is_first_child, new_ancestor_ids, top_parent_id)

immediate_parent_id = row.object_id
top_parent = top_parent_id
# Combine ancestor_ids to build the content id
data_content = new_ancestor_ids.join("-") + "-#{child_row.object_id}"

child_output.to_str.sub("<tr", %(<tr class="toggle-content" data-top-parent="#{id}_#{top_parent}" data-row-depth="#{current_depth}" data-row-parent="#{id}_#{immediate_parent_id}" data-advanced-table-content="#{data_content}"))
end.join.html_safe
child_data_attributes = {
top_parent: "#{id}_#{top_parent_id}",
row_depth: current_depth + 1,
row_parent: "#{id}_#{immediate_parent_id}",
advanced_table_content: data_content,
}

output << render_row_and_children(child_row, column_definitions, current_depth + 1, is_first_child, new_ancestor_ids, top_parent_id, additional_classes: "toggle-content", table_data_attributes: child_data_attributes)
end
end

output
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class TableRow < Playbook::KitBase
prop :depth
prop :collapsible_trail, type: Playbook::Props::Boolean,
default: true
prop :table_data_attributes, type: Playbook::Props::HashProp,
default: {}

def data
Hash(prop(:data)).merge(table_data_attributes)
end

def classname
generate_classname("pb_table_tr", "bg-white", subrow_depth_classname, separator: " ")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= pb_content_tag(:div) do %>
<%= pb_content_tag(:tr) do %>
<% object.column_definitions.each_with_index do |column, index| %>
<%= pb_rails("table/table_cell", props: { classname: object.td_classname}) do %>
<%= pb_rails("table/table_cell", props: { classname: "id-cell chrome-styles"}) do %>
<%= pb_rails("flex", props:{ align: "center", justify: "start" }) do %>
<% if collapsible_trail && index.zero? %>
<% (1..depth).each do |i| %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ class TableSubrowHeader < Playbook::KitBase
default: ""
prop :collapsible_trail, type: Playbook::Props::Boolean,
default: true
prop :subrow_data_attributes, type: Playbook::Props::HashProp,
default: {}

def classname
generate_classname("pb_table_tr", "bg-white", subrow_depth_classname, separator: " ")
def data
Hash(prop(:data)).merge(subrow_data_attributes)
end

def td_classname
generate_classname("id-cell", "chrome-styles", separator: " ")
def classname
generate_classname("pb_table_tr", "bg-silver", "pb_subrow_header", subrow_depth_classname, separator: " ")
end

private
Expand Down
Loading