keystone_ui 0.44.0 → 0.45.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 399e1a496d6abbf8fc37149cbf05ea62223222c1cf6b5678dc400b286a17f06a
4
- data.tar.gz: 5d7566e89343b57e8a35a6693e4fe6107184203299a880d58eab541b6ff16d81
3
+ metadata.gz: 978bd820f9629e5a312c465218ba68c9f055edbf7d4e740b450ffc935541ef00
4
+ data.tar.gz: 1d210e3d67198f807e6ebd626de17c8f39ff98182409b6b1746061f1b63830f9
5
5
  SHA512:
6
- metadata.gz: e0e0ab5ac2704a8612ec78bd80987d61ddfaee104cf0eedf976075e8ea28b4d64ac26990e061055165d334f06c8951b0eb8083b6005cb666dd8d47fec7ec5a7f
7
- data.tar.gz: 8de679cd46c03c8c8856196fc1d73d87def5ab3910c7b142d744ab7fca02c8b011f0cea93a2a2b42979d677b84c7448c32880d2ab6783851506188622bba7c30
6
+ metadata.gz: 57965061e3a70ccd8ee5be0dd9c9ba7af36afac30278bcb84fa1ec19a74c2b135367bb4fddc06371b5c914d5a6ad2c1b8332dca913ec823aa6030a28028a514a
7
+ data.tar.gz: 2d8c7a55901017fc335b759596bf13a400ece07714e13a986029fa142cf94f287db343a8468555074d0847433ca227e9893466625b5c94da4d2edc936d371afc
@@ -3,10 +3,11 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class Column
6
- attr_reader :key, :header_text
6
+ attr_reader :key, :header_text, :align
7
7
 
8
- def initialize(key, header_text, mobile_hidden: false, sortable: false, hideable: false, locked: false)
8
+ def initialize(key, header_text, mobile_hidden: false, sortable: false, hideable: false, locked: false, align: nil)
9
9
  @key = key
10
+ @align = align
10
11
  @header_text = header_text
11
12
  @mobile_hidden = mobile_hidden
12
13
  @sortable = sortable
@@ -36,6 +36,14 @@
36
36
  <% end %>
37
37
  <% else %>
38
38
  <% @items.each_with_index do |item, idx| %>
39
+ <% if (group = group_starting_at(idx)) %>
40
+ <tr class="<%= Keystone::Ui::DataTableComponent::HEAD_CLASSES %>" data-table-group>
41
+ <% group_cells(group).each do |cell| %>
42
+ <th scope="colgroup" class="<%= cell[:classes] %>"><%= cell[:value] %></th>
43
+ <% end %>
44
+ <% if actions? %><th></th><% end %>
45
+ </tr>
46
+ <% end %>
39
47
  <tr>
40
48
  <% row_cells[idx].each do |cell| %>
41
49
  <td class="<%= cell[:classes] %>">
@@ -60,5 +68,15 @@
60
68
  <% end %>
61
69
  <% end %>
62
70
  </tbody>
71
+ <% if total_cells.any? %>
72
+ <tfoot class="<%= Keystone::Ui::DataTableComponent::HEAD_CLASSES %>">
73
+ <tr>
74
+ <% total_cells.each do |cell| %>
75
+ <th scope="row" class="<%= cell[:classes] %>"><%= cell[:value] %></th>
76
+ <% end %>
77
+ <% if actions? %><th></th><% end %>
78
+ </tr>
79
+ </tfoot>
80
+ <% end %>
63
81
  </table>
64
82
  </div>
@@ -16,6 +16,7 @@ module Keystone
16
16
  ROW_CLASSES_MIDDLE = "ks-table-cell-middle text-sm whitespace-nowrap"
17
17
  ROW_CLASSES_LAST = "ks-table-cell-last text-right text-sm whitespace-nowrap"
18
18
 
19
+ ALIGN_CLASSES = { start: "text-left", end: "text-right" }.freeze
19
20
  MOBILE_HIDDEN_CLASSES = "hidden sm:table-cell"
20
21
  HEADER_LOCKED_CLASSES = "ks-table-header-locked sticky left-0"
21
22
  CELL_LOCKED_CLASSES = "ks-table-cell-locked sticky left-0"
@@ -29,8 +30,11 @@ module Keystone
29
30
  SORT_DESC_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .75.75v10.638l3.96-4.158a.75.75 0 1 1 1.08 1.04l-5.25 5.5a.75.75 0 0 1-1.08 0l-5.25-5.5a.75.75 0 0 1 1.08-1.04l3.96 4.158V3.75A.75.75 0 0 1 10 3Z" clip-rule="evenodd" /></svg>'
30
31
  SORT_NEUTRAL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .55.24l3.25 3.5a.75.75 0 1 1-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 0 1-1.1-1.02l3.25-3.5A.75.75 0 0 1 10 3Zm-3.76 9.2a.75.75 0 0 1 1.06.04l2.7 2.908 2.7-2.908a.75.75 0 1 1 1.1 1.02l-3.25 3.5a.75.75 0 0 1-1.1 0l-3.25-3.5a.75.75 0 0 1 .04-1.06Z" clip-rule="evenodd" /></svg>'
31
32
 
32
- def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)
33
+ def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil, group_by: nil, group_totals: {}, total: nil)
33
34
  @items = items.to_a
35
+ @group_by = group_by
36
+ @group_totals = group_totals.to_h.transform_keys(&:to_s)
37
+ @total = total&.to_h&.transform_keys(&:to_s)
34
38
  @all_columns = columns.map { |col| normalize_column(col) }
35
39
  @default_hidden = hidden_columns
36
40
  @layout = SavedLayout.new(columns: @all_columns, value: nil, default_hidden: hidden_columns)
@@ -83,7 +87,7 @@ module Keystone
83
87
 
84
88
  cell = {
85
89
  label: column.header_text,
86
- classes: tokens.join(" "),
90
+ classes: aligned(tokens.join(" "), column),
87
91
  scope: "col"
88
92
  }
89
93
 
@@ -127,7 +131,7 @@ module Keystone
127
131
 
128
132
  cell = {
129
133
  value: resolve_value(item, column.key),
130
- classes: tokens.join(" ")
134
+ classes: aligned(tokens.join(" "), column)
131
135
  }
132
136
 
133
137
  link_block = @link_blocks[column.key]
@@ -146,6 +150,28 @@ module Keystone
146
150
  visual_column_count
147
151
  end
148
152
 
153
+ def group_starting_at(index)
154
+ return unless @group_by
155
+
156
+ name = resolve_value(@items[index], @group_by)
157
+ name if index.zero? || name != resolve_value(@items[index - 1], @group_by)
158
+ end
159
+
160
+ def total_cells
161
+ return [] unless @total
162
+
163
+ @columns.map.with_index do |column, index|
164
+ { value: @total[column.key.to_s], classes: aligned(header_classes_for(index), column) }
165
+ end
166
+ end
167
+
168
+ def group_cells(name)
169
+ subtotals = @group_totals.fetch(name.to_s, {}).to_h.transform_keys(&:to_s)
170
+ @columns.map.with_index do |column, index|
171
+ { value: index.zero? ? name : subtotals[column.key.to_s], classes: aligned(header_classes_for(index), column) }
172
+ end
173
+ end
174
+
149
175
  private
150
176
 
151
177
  def apply_saved_layout
@@ -170,6 +196,12 @@ module Keystone
170
196
  end
171
197
  end
172
198
 
199
+ def aligned(classes, column)
200
+ return classes unless column.align
201
+
202
+ [ *classes.split.grep_v(/\Atext-(left|right)\z/), ALIGN_CLASSES.fetch(column.align) ].join(" ")
203
+ end
204
+
173
205
  def resolve_value(item, key)
174
206
  if item.respond_to?(key)
175
207
  item.public_send(key)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.44.0"
4
+ VERSION = "0.45.0"
5
5
  end
@@ -333,13 +333,18 @@ two exceptions: `ui_page`'s `padding:` treats any value other than `:none` as
333
333
 
334
334
  8. Build tables.
335
335
 
336
- - `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)`
336
+ - `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil, group_by: nil, group_totals: {}, total: nil)`
337
337
  takes a block yielding the table. `items:` are records or hashes, and a
338
338
  cell's value is the column key called on the item, or `item[key]`.
339
+ `group_by:` lists rows under heading rows named by that key's value,
340
+ `group_totals:` (`{ "Group name" => { column_key => value } }`) puts
341
+ subtotals in each heading row, and `total:` (`{ column_key => value }`)
342
+ ends the table with a total row. Pass every subtotal and total already
343
+ calculated. `align: :start` or `:end` on a `Column` aligns it left or right.
339
344
  - `columns:` takes `{ key: "Label" }` hashes when every column is plain.
340
345
  Switch the whole set to `Keystone::Ui::Column` objects once one column
341
346
  needs an option.
342
- - `Keystone::Ui::Column.new(key, header_text, mobile_hidden: false, sortable: false, hideable: false, locked: false)`
347
+ - `Keystone::Ui::Column.new(key, header_text, mobile_hidden: false, sortable: false, hideable: false, locked: false, align: nil)`
343
348
  — `mobile_hidden:` hides the column below `sm:`, `sortable:` gives it a
344
349
  sort header, and `hideable:` lets it be hidden and moved.
345
350
  `locked: true` on the first column keeps it in view while the rest scrolls
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keystone_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.44.0
4
+ version: 0.45.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider