keystone_ui 0.36.0 → 0.37.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 +4 -4
- data/app/assets/javascripts/keystone_ui/column_picker_controller.js +19 -2
- data/app/components/keystone/ui/column_picker_component.html.erb +1 -0
- data/app/components/keystone/ui/column_picker_component.rb +5 -5
- data/app/components/keystone/ui/data_table_component.rb +6 -19
- data/app/components/keystone/ui/saved_layout.rb +46 -0
- data/lib/keystone_ui/version.rb +1 -1
- data/the_local/agents/keystone_ui-develop.md +10 -3
- data/the_local/agents/keystone_ui-info.md +6 -2
- data/the_local/agents/keystone_ui-install.md +5 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1534a3f721376c82b75b22a653e8bcee3a0509bcd3b09cd137c93c78e15110f
|
|
4
|
+
data.tar.gz: 0df6e2e29387563688ba68bc53d8c29dc69aa322aa86c84b6416c0e3af36f703
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1869494c71af590cd1fa49fcd1062b024df02950f571e5dcbd7deaaa508574ad0f0aa2bfc8e23b0dc10d35ca440a50bc12e5d18063c62888de9eb29c42c09b45
|
|
7
|
+
data.tar.gz: 45563016cb89280c2e97cca008236c9fc50ba4681486a53f0d82fc4066e7db68368ad412c43b512cb2ca4ccd4f359dd29339890e24854eae2ead04ed9db7f6db
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
2
|
|
|
3
3
|
export default class extends Controller {
|
|
4
|
-
static targets = ["menu", "option"]
|
|
4
|
+
static targets = ["menu", "option", "error"]
|
|
5
5
|
static values = { saveUrl: String }
|
|
6
6
|
|
|
7
7
|
connect() {
|
|
8
|
+
this.shown = this.optionTargets.map(option => [ option, this.checkboxIn(option).checked ])
|
|
8
9
|
this._close = this.close.bind(this)
|
|
9
10
|
document.addEventListener("click", this._close)
|
|
10
11
|
}
|
|
@@ -66,6 +67,10 @@ export default class extends Controller {
|
|
|
66
67
|
|
|
67
68
|
moved() {
|
|
68
69
|
this.changed = true
|
|
70
|
+
this.refreshMoveButtons()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
refreshMoveButtons() {
|
|
69
74
|
const options = this.optionTargets
|
|
70
75
|
options.forEach((option, index) => {
|
|
71
76
|
option.querySelector('[data-action="click->column-picker#moveUp"]').disabled = index === 0
|
|
@@ -99,8 +104,20 @@ export default class extends Controller {
|
|
|
99
104
|
"X-CSRF-Token": token
|
|
100
105
|
},
|
|
101
106
|
body: JSON.stringify({ hidden_columns: this.hiddenColumns(), column_order: this.columnOrder() })
|
|
102
|
-
}).then(() => {
|
|
107
|
+
}).then((response) => {
|
|
108
|
+
if (!response.ok) return this.failed()
|
|
109
|
+
|
|
103
110
|
Turbo.visit(window.location.href, { action: "replace" })
|
|
111
|
+
}).catch(() => this.failed())
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
failed() {
|
|
115
|
+
this.errorTarget.classList.remove("hidden")
|
|
116
|
+
this.shown.forEach(([ option, checked ]) => {
|
|
117
|
+
option.parentNode.insertBefore(option, null)
|
|
118
|
+
this.checkboxIn(option).checked = checked
|
|
119
|
+
option.querySelector("label").classList.toggle("ks-menu-option-hidden", !checked)
|
|
104
120
|
})
|
|
121
|
+
this.refreshMoveButtons()
|
|
105
122
|
}
|
|
106
123
|
}
|
|
@@ -11,6 +11,7 @@ module Keystone
|
|
|
11
11
|
OPTION_HIDDEN_CLASSES = "ks-menu-option-hidden"
|
|
12
12
|
OPTION_ROW_CLASSES = "flex items-center"
|
|
13
13
|
MOVE_BUTTON_CLASSES = "ks-menu-move text-sm"
|
|
14
|
+
ERROR_CLASSES = "ks-error hidden"
|
|
14
15
|
|
|
15
16
|
COLUMNS_ICON = <<~SVG.freeze
|
|
16
17
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4">
|
|
@@ -20,18 +21,17 @@ module Keystone
|
|
|
20
21
|
|
|
21
22
|
attr_reader :save_url
|
|
22
23
|
|
|
23
|
-
def initialize(columns:, hidden_columns: [], save_url: nil)
|
|
24
|
-
@
|
|
25
|
-
@hidden_keys = Array(hidden_columns).map(&:to_sym).to_set
|
|
24
|
+
def initialize(columns:, hidden_columns: [], save_url: nil, layout: nil)
|
|
25
|
+
@layout = layout || SavedLayout.new(columns: columns, value: nil, default_hidden: hidden_columns)
|
|
26
26
|
@save_url = save_url
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def hideable_columns
|
|
30
|
-
@columns.select(&:hideable?)
|
|
30
|
+
@layout.columns.select(&:hideable?)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def hidden?(key)
|
|
34
|
-
@
|
|
34
|
+
@layout.hidden?(key)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def option_classes(key)
|
|
@@ -32,8 +32,9 @@ module Keystone
|
|
|
32
32
|
def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)
|
|
33
33
|
@items = items.to_a
|
|
34
34
|
@all_columns = columns.map { |col| normalize_column(col) }
|
|
35
|
-
@
|
|
36
|
-
@
|
|
35
|
+
@default_hidden = hidden_columns
|
|
36
|
+
@layout = SavedLayout.new(columns: @all_columns, value: nil, default_hidden: hidden_columns)
|
|
37
|
+
@columns = @layout.visible_columns
|
|
37
38
|
@key = key
|
|
38
39
|
@empty_message = empty_message
|
|
39
40
|
@sort = sort&.to_sym
|
|
@@ -63,7 +64,7 @@ module Keystone
|
|
|
63
64
|
def column_picker
|
|
64
65
|
return unless @save_url
|
|
65
66
|
|
|
66
|
-
@column_picker ||= ColumnPickerComponent.new(columns: @all_columns,
|
|
67
|
+
@column_picker ||= ColumnPickerComponent.new(columns: @all_columns, layout: @layout, save_url: @save_url)
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
def column_keys
|
|
@@ -151,25 +152,11 @@ module Keystone
|
|
|
151
152
|
saved = KeystoneUi.configuration.supplied_preference(helpers, @key)
|
|
152
153
|
return unless saved
|
|
153
154
|
|
|
154
|
-
@
|
|
155
|
-
@
|
|
156
|
-
@columns = visible_columns(@hidden_columns)
|
|
155
|
+
@layout = SavedLayout.new(columns: @all_columns, value: saved[:value], default_hidden: @default_hidden)
|
|
156
|
+
@columns = @layout.visible_columns
|
|
157
157
|
@save_url = saved[:save_url]
|
|
158
158
|
end
|
|
159
159
|
|
|
160
|
-
def ordered_columns(column_order)
|
|
161
|
-
return @all_columns unless column_order
|
|
162
|
-
|
|
163
|
-
positions = Array(column_order).map(&:to_sym).each_with_index.to_h
|
|
164
|
-
hideable = @all_columns.select(&:hideable?).sort_by.with_index { |col, index| [ positions.fetch(col.key, positions.size + index) ] }
|
|
165
|
-
@all_columns.map { |col| col.hideable? ? hideable.shift : col }
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def visible_columns(hidden_columns)
|
|
169
|
-
hidden_keys = Array(hidden_columns).map(&:to_sym).to_set
|
|
170
|
-
@all_columns.reject { |col| col.hideable? && hidden_keys.include?(col.key) }
|
|
171
|
-
end
|
|
172
|
-
|
|
173
160
|
def visual_column_count
|
|
174
161
|
@columns.length + (actions? ? 1 : 0)
|
|
175
162
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Keystone
|
|
4
|
+
module Ui
|
|
5
|
+
class SavedLayout
|
|
6
|
+
def initialize(columns:, value:, default_hidden:)
|
|
7
|
+
@columns = columns
|
|
8
|
+
@value = value.is_a?(Hash) ? value : {}
|
|
9
|
+
@default_hidden = default_hidden
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def columns
|
|
13
|
+
@ordered_columns ||= ordered_columns
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def visible_columns
|
|
17
|
+
columns.reject { |column| hidden?(column.key) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def hidden?(key)
|
|
21
|
+
column = @columns.find { |col| col.key == key.to_sym }
|
|
22
|
+
column&.hideable? && hidden_keys.include?(key.to_sym)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def ordered_columns
|
|
28
|
+
column_order = saved_list("column_order")
|
|
29
|
+
return @columns unless column_order
|
|
30
|
+
|
|
31
|
+
positions = Array(column_order).map(&:to_sym).each_with_index.to_h
|
|
32
|
+
hideable = @columns.select(&:hideable?).sort_by.with_index { |col, index| positions.fetch(col.key, positions.size + index) }
|
|
33
|
+
@columns.map { |col| col.hideable? ? hideable.shift : col }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def hidden_keys
|
|
37
|
+
@hidden_keys ||= Array(saved_list("hidden_columns") || @default_hidden).map(&:to_sym).to_set
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def saved_list(name)
|
|
41
|
+
list = @value[name]
|
|
42
|
+
list if list.is_a?(Array)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/keystone_ui/version.rb
CHANGED
|
@@ -240,8 +240,11 @@ outer element. See Conventions before using it.
|
|
|
240
240
|
and the hideable ones fill the remaining places. With no `"column_order"` the
|
|
241
241
|
columns keep their declared order. Whenever the supplier
|
|
242
242
|
returns a save address, the table renders a "Columns" menu in a row above
|
|
243
|
-
itself, aligned right, that saves to it as `ui_column_picker` does
|
|
244
|
-
for a person with nothing saved
|
|
243
|
+
itself, aligned right, that saves to it as `ui_column_picker` does and shows
|
|
244
|
+
the same message when a save fails, including for a person with nothing saved
|
|
245
|
+
yet. That menu lists the hideable columns in
|
|
246
|
+
the order the table shows them and leaves ticked exactly the ones the table
|
|
247
|
+
shows. When the
|
|
245
248
|
supplier returns nothing, when no supplier is set, or when no `key:` is
|
|
246
249
|
passed, the table renders from `hidden_columns:` with no Columns menu. In
|
|
247
250
|
every case `hidden_columns:` is the table's default layout.
|
|
@@ -269,7 +272,11 @@ outer element. See Conventions before using it.
|
|
|
269
272
|
`X-CSRF-Token` header, then reloads the page. A menu closed with nothing
|
|
270
273
|
changed sends nothing. `column_order` lists every hideable column's key in
|
|
271
274
|
the menu's order when it closes. With no `save_url:` it sends nothing. The app must provide that endpoint and persist
|
|
272
|
-
both lists. The
|
|
275
|
+
both lists. The endpoint must answer with a success status when it has saved
|
|
276
|
+
them. When it answers with an error status, or the request cannot reach the
|
|
277
|
+
server, the menu does not reload the page: it shows "Your column changes were
|
|
278
|
+
not saved." under the Columns button, and puts its boxes and its order back
|
|
279
|
+
to what the table shows. The picker does not reorder the table: beside a table without
|
|
273
280
|
`key:`, the app must pass the table and the picker its columns in the saved
|
|
274
281
|
order itself. A table
|
|
275
282
|
given `key:` renders its own Columns menu when the supplier gives a save
|
|
@@ -150,11 +150,15 @@ holds the catalog.
|
|
|
150
150
|
table, at its right, and saves the user's choice there, even before anything
|
|
151
151
|
has been saved. The menu lists the hideable columns in the order the table
|
|
152
152
|
shows them, each with a box to show or hide it and buttons to move it up or
|
|
153
|
-
down.
|
|
153
|
+
down. The menu and the table read the same saved layout, so the menu's
|
|
154
|
+
ticked boxes and order always match the columns the table shows. An unticked column's name is greyed at once. Ticking boxes and moving
|
|
154
155
|
columns sends nothing while the menu is open. Closing the menu, with its
|
|
155
156
|
Columns button or by clicking anywhere outside it, saves the hidden columns
|
|
156
157
|
and the order together once, then reloads the page. Closing it with nothing
|
|
157
|
-
changed saves nothing.
|
|
158
|
+
changed saves nothing. When the save is refused or cannot reach the server,
|
|
159
|
+
the page does not reload. The Columns menu shows the message "Your
|
|
160
|
+
column changes were not saved." and puts its boxes and order back to what
|
|
161
|
+
the table shows.
|
|
158
162
|
A table with no key, or an app with no supplier, renders from its own call
|
|
159
163
|
alone. Setting up the supplier belongs to the install local.
|
|
160
164
|
- **Suggestions.** A form field can carry a list of suggested values. The
|
|
@@ -282,6 +282,11 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
282
282
|
string keys, `"hidden_columns"` and `"column_order"`, or the saved order
|
|
283
283
|
is not applied. With no `save_url`, the saved layout applies and no menu
|
|
284
284
|
is shown.
|
|
285
|
+
- The action at `save_url` must answer a stored layout with a 2xx status.
|
|
286
|
+
Any other status, or a request that cannot reach the server, leaves the
|
|
287
|
+
page unreloaded. The table then shows "Your column changes were not
|
|
288
|
+
saved." beside its Columns button, and the menu's boxes and order go back
|
|
289
|
+
to what the table shows.
|
|
285
290
|
- A companion preferences gem may set this supplier for the app. Ask the
|
|
286
291
|
developer whether the app uses one, or which code stores each user's table
|
|
287
292
|
layouts, before writing the callable.
|
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.
|
|
4
|
+
version: 0.37.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -175,6 +175,7 @@ files:
|
|
|
175
175
|
- app/components/keystone/ui/progress_component.rb
|
|
176
176
|
- app/components/keystone/ui/radio_card_component.html.erb
|
|
177
177
|
- app/components/keystone/ui/radio_card_component.rb
|
|
178
|
+
- app/components/keystone/ui/saved_layout.rb
|
|
178
179
|
- app/components/keystone/ui/section_component.html.erb
|
|
179
180
|
- app/components/keystone/ui/section_component.rb
|
|
180
181
|
- app/components/keystone/ui/select_component.html.erb
|